From sabre at nondot.org Mon Mar 15 00:35:37 2010 From: sabre at nondot.org (Chris Lattner) Date: Mon, 15 Mar 2010 05:35:37 -0000 Subject: [llvm-commits] [llvm] r98530 - /llvm/trunk/lib/Target/Alpha/AlphaInstrInfo.td Message-ID: <20100315053537.935A02A6C12C@llvm.org> Author: lattner Date: Mon Mar 15 00:35:37 2010 New Revision: 98530 URL: http://llvm.org/viewvc/llvm-project?rev=98530&view=rev Log: add some missing types Modified: llvm/trunk/lib/Target/Alpha/AlphaInstrInfo.td Modified: llvm/trunk/lib/Target/Alpha/AlphaInstrInfo.td URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Target/Alpha/AlphaInstrInfo.td?rev=98530&r1=98529&r2=98530&view=diff ============================================================================== --- llvm/trunk/lib/Target/Alpha/AlphaInstrInfo.td (original) +++ llvm/trunk/lib/Target/Alpha/AlphaInstrInfo.td Mon Mar 15 00:35:37 2010 @@ -1059,8 +1059,8 @@ def : Pat<(i64 immSExt16int:$imm), (ZAPNOTi (LDA (SExt16 immSExt16int:$imm), R31), 15)>; def : Pat<(i64 immConst2PartInt:$imm), - (ZAPNOTi (LDA (LL16 (SExt32 immConst2PartInt:$imm)), - (LDAH (LH16 (SExt32 immConst2PartInt:$imm)), R31)), 15)>; + (ZAPNOTi (LDA (LL16 (i64 (SExt32 immConst2PartInt:$imm))), + (LDAH (LH16 (i64 (SExt32 immConst2PartInt:$imm))), R31)), 15)>; //TODO: I want to just define these like this! From sabre at nondot.org Mon Mar 15 00:53:30 2010 From: sabre at nondot.org (Chris Lattner) Date: Mon, 15 Mar 2010 05:53:30 -0000 Subject: [llvm-commits] [llvm] r98531 - in /llvm/trunk/lib/Target/X86: X86InstrMMX.td X86InstrSSE.td Message-ID: <20100315055331.0F7D82A6C12C@llvm.org> Author: lattner Date: Mon Mar 15 00:53:30 2010 New Revision: 98531 URL: http://llvm.org/viewvc/llvm-project?rev=98531&view=rev Log: fix a few more ambiguous types. Modified: llvm/trunk/lib/Target/X86/X86InstrMMX.td llvm/trunk/lib/Target/X86/X86InstrSSE.td Modified: llvm/trunk/lib/Target/X86/X86InstrMMX.td URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Target/X86/X86InstrMMX.td?rev=98531&r1=98530&r2=98531&view=diff ============================================================================== --- llvm/trunk/lib/Target/X86/X86InstrMMX.td (original) +++ llvm/trunk/lib/Target/X86/X86InstrMMX.td Mon Mar 15 00:53:30 2010 @@ -272,9 +272,9 @@ // Shift up / down and insert zero's. def : Pat<(v1i64 (X86vshl VR64:$src, (i8 imm:$amt))), - (MMX_PSLLQri VR64:$src, imm:$amt)>; + (MMX_PSLLQri VR64:$src, (GetLo32XForm imm:$amt))>; def : Pat<(v1i64 (X86vshr VR64:$src, (i8 imm:$amt))), - (MMX_PSRLQri VR64:$src, imm:$amt)>; + (MMX_PSRLQri VR64:$src, (GetLo32XForm imm:$amt))>; // Comparison Instructions defm MMX_PCMPEQB : MMXI_binop_rm_int<0x74, "pcmpeqb", int_x86_mmx_pcmpeq_b>; Modified: llvm/trunk/lib/Target/X86/X86InstrSSE.td URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Target/X86/X86InstrSSE.td?rev=98531&r1=98530&r2=98531&view=diff ============================================================================== --- llvm/trunk/lib/Target/X86/X86InstrSSE.td (original) +++ llvm/trunk/lib/Target/X86/X86InstrSSE.td Mon Mar 15 00:53:30 2010 @@ -379,7 +379,7 @@ def MOVSSrr : SSI<0x10, MRMSrcReg, (outs VR128:$dst), (ins VR128:$src1, FR32:$src2), "movss\t{$src2, $dst|$dst, $src2}", - [(set VR128:$dst, + [(set (v4f32 VR128:$dst), (movl VR128:$src1, (scalar_to_vector FR32:$src2)))]>; // Extract the low 32-bit value from one vector and insert it into another. @@ -1141,7 +1141,7 @@ def MOVSDrr : SDI<0x10, MRMSrcReg, (outs VR128:$dst), (ins VR128:$src1, FR64:$src2), "movsd\t{$src2, $dst|$dst, $src2}", - [(set VR128:$dst, + [(set (v2f64 VR128:$dst), (movl VR128:$src1, (scalar_to_vector FR64:$src2)))]>; // Extract the low 64-bit value from one vector and insert it into another. From sabre at nondot.org Mon Mar 15 00:53:48 2010 From: sabre at nondot.org (Chris Lattner) Date: Mon, 15 Mar 2010 05:53:48 -0000 Subject: [llvm-commits] [llvm] r98532 - in /llvm/trunk/lib/Target/CellSPU: CellSDKIntrinsics.td SPU64InstrInfo.td SPUInstrInfo.td SPUOperands.td Message-ID: <20100315055348.20D0F2A6C12C@llvm.org> Author: lattner Date: Mon Mar 15 00:53:47 2010 New Revision: 98532 URL: http://llvm.org/viewvc/llvm-project?rev=98532&view=rev Log: do some serious surgery on CellSPU to get it back into a world where it uses types consistently. Modified: llvm/trunk/lib/Target/CellSPU/CellSDKIntrinsics.td llvm/trunk/lib/Target/CellSPU/SPU64InstrInfo.td llvm/trunk/lib/Target/CellSPU/SPUInstrInfo.td llvm/trunk/lib/Target/CellSPU/SPUOperands.td Modified: llvm/trunk/lib/Target/CellSPU/CellSDKIntrinsics.td URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Target/CellSPU/CellSDKIntrinsics.td?rev=98532&r1=98531&r2=98532&view=diff ============================================================================== --- llvm/trunk/lib/Target/CellSPU/CellSDKIntrinsics.td (original) +++ llvm/trunk/lib/Target/CellSPU/CellSDKIntrinsics.td Mon Mar 15 00:53:47 2010 @@ -205,10 +205,9 @@ // Shift/rotate intrinsics: //===----------------------------------------------------------------------===// -/* FIXME: These have (currently unenforced) type conflicts. */ def CellSDKshli: Pat<(int_spu_si_shli (v4i32 VECREG:$rA), uimm7:$val), - (SHLIv4i32 VECREG:$rA, uimm7:$val)>; + (SHLIv4i32 VECREG:$rA, (TO_IMM32 imm:$val))>; def CellSDKshlqbi: Pat<(int_spu_si_shlqbi VECREG:$rA, R32C:$rB), @@ -216,7 +215,7 @@ def CellSDKshlqii: Pat<(int_spu_si_shlqbii VECREG:$rA, uimm7:$val), - (SHLQBIIv16i8 VECREG:$rA, uimm7:$val)>; + (SHLQBIIv16i8 VECREG:$rA, (TO_IMM32 imm:$val))>; def CellSDKshlqby: Pat<(int_spu_si_shlqby VECREG:$rA, R32C:$rB), @@ -224,7 +223,8 @@ def CellSDKshlqbyi: Pat<(int_spu_si_shlqbyi VECREG:$rA, uimm7:$val), - (SHLQBYIv16i8 VECREG:$rA, uimm7:$val)>; + (SHLQBYIv16i8 VECREG:$rA, (TO_IMM32 imm:$val))>; + //===----------------------------------------------------------------------===// // Branch/compare intrinsics: Modified: llvm/trunk/lib/Target/CellSPU/SPU64InstrInfo.td URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Target/CellSPU/SPU64InstrInfo.td?rev=98532&r1=98531&r2=98532&view=diff ============================================================================== --- llvm/trunk/lib/Target/CellSPU/SPU64InstrInfo.td (original) +++ llvm/trunk/lib/Target/CellSPU/SPU64InstrInfo.td Mon Mar 15 00:53:47 2010 @@ -155,8 +155,9 @@ defm I64LGE: CompareLogicalGreaterEqual64; def : Pat<(setuge R64C:$rA, R64C:$rB), I64LGEr64.Fragment>; -def : Pat<(setuge (v2i64 VECREG:$rA), (v2i64 VECREG:$rB)), - I64LGEv2i64.Fragment>; +def : Pat<(v2i64 (setuge (v2i64 VECREG:$rA), (v2i64 VECREG:$rB))), + I64LGEv2i64.Fragment>; + // i64 setult: def : I64SETCCNegCond; @@ -233,8 +234,8 @@ defm I64GE: CompareGreaterEqual64; def : Pat<(setge R64C:$rA, R64C:$rB), I64GEr64.Fragment>; -def : Pat<(setge (v2i64 VECREG:$rA), (v2i64 VECREG:$rB)), - I64GEv2i64.Fragment>; +def : Pat<(v2i64 (setge (v2i64 VECREG:$rA), (v2i64 VECREG:$rB))), + I64GEv2i64.Fragment>; // i64 setult: def : I64SETCCNegCond; Modified: llvm/trunk/lib/Target/CellSPU/SPUInstrInfo.td URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Target/CellSPU/SPUInstrInfo.td?rev=98532&r1=98531&r2=98532&view=diff ============================================================================== --- llvm/trunk/lib/Target/CellSPU/SPUInstrInfo.td (original) +++ llvm/trunk/lib/Target/CellSPU/SPUInstrInfo.td Mon Mar 15 00:53:47 2010 @@ -2179,10 +2179,10 @@ defm SHLHI : ShiftLeftHalfwordImm; def : Pat<(SPUvec_shl (v8i16 VECREG:$rA), (i32 uimm7:$val)), - (SHLHIv8i16 VECREG:$rA, uimm7:$val)>; + (SHLHIv8i16 VECREG:$rA, (TO_IMM16 uimm7:$val))>; def : Pat<(shl R16C:$rA, (i32 uimm7:$val)), - (SHLHIr16 R16C:$rA, uimm7:$val)>; + (SHLHIr16 R16C:$rA, (TO_IMM16 uimm7:$val))>; //===----------------------------------------------------------------------===// @@ -2410,8 +2410,8 @@ defm ROTHI: RotateLeftHalfwordImm; -def : Pat<(SPUvec_rotl VECREG:$rA, (i32 uimm7:$val)), - (ROTHIv8i16 VECREG:$rA, imm:$val)>; +def : Pat<(SPUvec_rotl (v8i16 VECREG:$rA), (i32 uimm7:$val)), + (ROTHIv8i16 VECREG:$rA, (TO_IMM16 imm:$val))>; //-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~ // Rotate word: @@ -2682,10 +2682,10 @@ (ROTHMIv8i16 VECREG:$rA, imm:$val)>; def: Pat<(SPUvec_srl (v8i16 VECREG:$rA), (i16 imm:$val)), - (ROTHMIv8i16 VECREG:$rA, imm:$val)>; + (ROTHMIv8i16 VECREG:$rA, (TO_IMM32 imm:$val))>; def: Pat<(SPUvec_srl (v8i16 VECREG:$rA), (i8 imm:$val)), - (ROTHMIv8i16 VECREG:$rA, imm:$val)>; + (ROTHMIv8i16 VECREG:$rA, (TO_IMM32 imm:$val))>; def ROTHMIr16: ROTHMIInst<(outs R16C:$rT), (ins R16C:$rA, rothNeg7imm:$val), @@ -2695,10 +2695,10 @@ (ROTHMIr16 R16C:$rA, uimm7:$val)>; def: Pat<(srl R16C:$rA, (i16 uimm7:$val)), - (ROTHMIr16 R16C:$rA, uimm7:$val)>; + (ROTHMIr16 R16C:$rA, (TO_IMM32 uimm7:$val))>; def: Pat<(srl R16C:$rA, (i8 uimm7:$val)), - (ROTHMIr16 R16C:$rA, uimm7:$val)>; + (ROTHMIr16 R16C:$rA, (TO_IMM32 uimm7:$val))>; // ROTM v4i32 form: See the ROTHM v8i16 comments. class ROTMInst pattern>: @@ -2709,14 +2709,14 @@ ROTMInst<(outs VECREG:$rT), (ins VECREG:$rA, R32C:$rB), [/* see patterns below - $rB must be negated */]>; -def : Pat<(SPUvec_srl VECREG:$rA, R32C:$rB), +def : Pat<(SPUvec_srl (v4i32 VECREG:$rA), R32C:$rB), (ROTMv4i32 VECREG:$rA, (SFIr32 R32C:$rB, 0))>; -def : Pat<(SPUvec_srl VECREG:$rA, R16C:$rB), +def : Pat<(SPUvec_srl (v4i32 VECREG:$rA), R16C:$rB), (ROTMv4i32 VECREG:$rA, (SFIr32 (XSHWr16 R16C:$rB), 0))>; -def : Pat<(SPUvec_srl VECREG:$rA, R8C:$rB), +def : Pat<(SPUvec_srl (v4i32 VECREG:$rA), R8C:$rB), (ROTMv4i32 VECREG:$rA, (SFIr32 (XSHWr16 (XSBHr8 R8C:$rB)), 0))>; @@ -2742,11 +2742,11 @@ [(set (v4i32 VECREG:$rT), (SPUvec_srl VECREG:$rA, (i32 uimm7:$val)))]>; -def : Pat<(SPUvec_srl VECREG:$rA, (i16 uimm7:$val)), - (ROTMIv4i32 VECREG:$rA, uimm7:$val)>; +def : Pat<(SPUvec_srl (v4i32 VECREG:$rA), (i16 uimm7:$val)), + (ROTMIv4i32 VECREG:$rA, (TO_IMM32 uimm7:$val))>; -def : Pat<(SPUvec_srl VECREG:$rA, (i8 uimm7:$val)), - (ROTMIv4i32 VECREG:$rA, uimm7:$val)>; +def : Pat<(SPUvec_srl (v4i32 VECREG:$rA), (i8 uimm7:$val)), + (ROTMIv4i32 VECREG:$rA, (TO_IMM32 uimm7:$val))>; // ROTMI r32 form: know how to complement the immediate value. def ROTMIr32: @@ -2755,10 +2755,10 @@ [(set R32C:$rT, (srl R32C:$rA, (i32 uimm7:$val)))]>; def : Pat<(srl R32C:$rA, (i16 imm:$val)), - (ROTMIr32 R32C:$rA, uimm7:$val)>; + (ROTMIr32 R32C:$rA, (TO_IMM32 uimm7:$val))>; def : Pat<(srl R32C:$rA, (i8 imm:$val)), - (ROTMIr32 R32C:$rA, uimm7:$val)>; + (ROTMIr32 R32C:$rA, (TO_IMM32 uimm7:$val))>; //-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~ // ROTQMBY: This is a vector form merely so that when used in an @@ -2916,14 +2916,14 @@ "rotmah\t$rT, $rA, $rB", RotateShift, [/* see patterns below - $rB must be negated */]>; -def : Pat<(SPUvec_sra VECREG:$rA, R32C:$rB), +def : Pat<(SPUvec_sra (v8i16 VECREG:$rA), R32C:$rB), (ROTMAHv8i16 VECREG:$rA, (SFIr32 R32C:$rB, 0))>; -def : Pat<(SPUvec_sra VECREG:$rA, R16C:$rB), +def : Pat<(SPUvec_sra (v8i16 VECREG:$rA), R16C:$rB), (ROTMAHv8i16 VECREG:$rA, (SFIr32 (XSHWr16 R16C:$rB), 0))>; -def : Pat<(SPUvec_sra VECREG:$rA, R8C:$rB), +def : Pat<(SPUvec_sra (v8i16 VECREG:$rA), R8C:$rB), (ROTMAHv8i16 VECREG:$rA, (SFIr32 (XSHWr16 (XSBHr8 R8C:$rB)), 0))>; @@ -2950,10 +2950,10 @@ (SPUvec_sra (v8i16 VECREG:$rA), (i32 uimm7:$val)))]>; def : Pat<(SPUvec_sra (v8i16 VECREG:$rA), (i16 uimm7:$val)), - (ROTMAHIv8i16 (v8i16 VECREG:$rA), (i32 uimm7:$val))>; + (ROTMAHIv8i16 (v8i16 VECREG:$rA), (TO_IMM32 uimm7:$val))>; def : Pat<(SPUvec_sra (v8i16 VECREG:$rA), (i8 uimm7:$val)), - (ROTMAHIv8i16 (v8i16 VECREG:$rA), (i32 uimm7:$val))>; + (ROTMAHIv8i16 (v8i16 VECREG:$rA), (TO_IMM32 uimm7:$val))>; def ROTMAHIr16: RRForm<0b01111110000, (outs R16C:$rT), (ins R16C:$rA, rothNeg7imm_i16:$val), @@ -2961,25 +2961,25 @@ [(set R16C:$rT, (sra R16C:$rA, (i16 uimm7:$val)))]>; def : Pat<(sra R16C:$rA, (i32 imm:$val)), - (ROTMAHIr16 R16C:$rA, uimm7:$val)>; + (ROTMAHIr16 R16C:$rA, (TO_IMM32 uimm7:$val))>; def : Pat<(sra R16C:$rA, (i8 imm:$val)), - (ROTMAHIr16 R16C:$rA, uimm7:$val)>; + (ROTMAHIr16 R16C:$rA, (TO_IMM32 uimm7:$val))>; def ROTMAv4i32: RRForm<0b01011010000, (outs VECREG:$rT), (ins VECREG:$rA, R32C:$rB), "rotma\t$rT, $rA, $rB", RotateShift, [/* see patterns below - $rB must be negated */]>; -def : Pat<(SPUvec_sra VECREG:$rA, R32C:$rB), - (ROTMAv4i32 (v4i32 VECREG:$rA), (SFIr32 R32C:$rB, 0))>; +def : Pat<(SPUvec_sra (v4i32 VECREG:$rA), R32C:$rB), + (ROTMAv4i32 VECREG:$rA, (SFIr32 R32C:$rB, 0))>; -def : Pat<(SPUvec_sra VECREG:$rA, R16C:$rB), - (ROTMAv4i32 (v4i32 VECREG:$rA), +def : Pat<(SPUvec_sra (v4i32 VECREG:$rA), R16C:$rB), + (ROTMAv4i32 VECREG:$rA, (SFIr32 (XSHWr16 R16C:$rB), 0))>; -def : Pat<(SPUvec_sra VECREG:$rA, R8C:$rB), - (ROTMAv4i32 (v4i32 VECREG:$rA), +def : Pat<(SPUvec_sra (v4i32 VECREG:$rA), R8C:$rB), + (ROTMAv4i32 VECREG:$rA, (SFIr32 (XSHWr16 (XSBHr8 R8C:$rB)), 0))>; def ROTMAr32: Modified: llvm/trunk/lib/Target/CellSPU/SPUOperands.td URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Target/CellSPU/SPUOperands.td?rev=98532&r1=98531&r2=98532&view=diff ============================================================================== --- llvm/trunk/lib/Target/CellSPU/SPUOperands.td (original) +++ llvm/trunk/lib/Target/CellSPU/SPUOperands.td Mon Mar 15 00:53:47 2010 @@ -9,6 +9,17 @@ // Cell SPU Instruction Operands: //===----------------------------------------------------------------------===// +// TO_IMM32 - Convert an i8/i16 to i32. +def TO_IMM32 : SDNodeXFormgetZExtValue()); +}]>; + +// TO_IMM16 - Convert an i8/i32 to i16. +def TO_IMM16 : SDNodeXFormgetTargetConstant(N->getZExtValue(), MVT::i16); +}]>; + + def LO16 : SDNodeXFormgetZExtValue(); // Transformation function: get the low 16 bits. From sabre at nondot.org Mon Mar 15 00:55:36 2010 From: sabre at nondot.org (Chris Lattner) Date: Mon, 15 Mar 2010 05:55:36 -0000 Subject: [llvm-commits] [llvm] r98533 - /llvm/trunk/include/llvm/CodeGen/MachineLocation.h Message-ID: <20100315055536.117FF2A6C12C@llvm.org> Author: lattner Date: Mon Mar 15 00:55:35 2010 New Revision: 98533 URL: http://llvm.org/viewvc/llvm-project?rev=98533&view=rev Log: MachineMove ctor doesn't need to to mutate input, add 'const' Modified: llvm/trunk/include/llvm/CodeGen/MachineLocation.h Modified: llvm/trunk/include/llvm/CodeGen/MachineLocation.h URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/CodeGen/MachineLocation.h?rev=98533&r1=98532&r2=98533&view=diff ============================================================================== --- llvm/trunk/include/llvm/CodeGen/MachineLocation.h (original) +++ llvm/trunk/include/llvm/CodeGen/MachineLocation.h Mon Mar 15 00:55:35 2010 @@ -78,7 +78,8 @@ public: MachineMove() : Label(0) {} - MachineMove(MCSymbol *label, MachineLocation &D, MachineLocation &S) + MachineMove(MCSymbol *label, const MachineLocation &D, + const MachineLocation &S) : Label(label), Destination(D), Source(S) {} // Accessors From sabre at nondot.org Mon Mar 15 01:00:16 2010 From: sabre at nondot.org (Chris Lattner) Date: Mon, 15 Mar 2010 06:00:16 -0000 Subject: [llvm-commits] [llvm] r98534 - in /llvm/trunk/utils/TableGen: CodeGenDAGPatterns.cpp CodeGenDAGPatterns.h CodeGenTarget.cpp CodeGenTarget.h DAGISelEmitter.cpp DAGISelMatcherGen.cpp FastISelEmitter.cpp Message-ID: <20100315060016.82CF92A6C12C@llvm.org> Author: lattner Date: Mon Mar 15 01:00:16 2010 New Revision: 98534 URL: http://llvm.org/viewvc/llvm-project?rev=98534&view=rev Log: Completely rewrite tblgen's type inference mechanism, changing the primary datastructure from being a "std::vector" to being a new TypeSet class that actually has (gasp) invariants! This changes more things than I remember, but one major innovation here is that it enforces that named input values agree in type with their output values. This also eliminates code that transparently assumes (in some cases) that SDNodeXForm input/output types are the same, because this is wrong in many case. This also eliminates a bug which caused a lot of ambiguous patterns to go undetected, where a register class would sometimes pick the first possible type, causing an ambiguous pattern to get arbitrary results. With all the recent target changes, this causes no functionality change! Modified: llvm/trunk/utils/TableGen/CodeGenDAGPatterns.cpp llvm/trunk/utils/TableGen/CodeGenDAGPatterns.h llvm/trunk/utils/TableGen/CodeGenTarget.cpp llvm/trunk/utils/TableGen/CodeGenTarget.h llvm/trunk/utils/TableGen/DAGISelEmitter.cpp llvm/trunk/utils/TableGen/DAGISelMatcherGen.cpp llvm/trunk/utils/TableGen/FastISelEmitter.cpp Modified: llvm/trunk/utils/TableGen/CodeGenDAGPatterns.cpp URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/utils/TableGen/CodeGenDAGPatterns.cpp?rev=98534&r1=98533&r2=98534&view=diff ============================================================================== --- llvm/trunk/utils/TableGen/CodeGenDAGPatterns.cpp (original) +++ llvm/trunk/utils/TableGen/CodeGenDAGPatterns.cpp Mon Mar 15 01:00:16 2010 @@ -15,44 +15,17 @@ #include "CodeGenDAGPatterns.h" #include "Record.h" #include "llvm/ADT/StringExtras.h" +#include "llvm/ADT/STLExtras.h" #include "llvm/Support/Debug.h" #include #include -#include using namespace llvm; //===----------------------------------------------------------------------===// -// Helpers for working with extended types. - -/// FilterVTs - Filter a list of VT's according to a predicate. -/// -template -static std::vector -FilterVTs(const std::vector &InVTs, T Filter) { - std::vector Result; - for (unsigned i = 0, e = InVTs.size(); i != e; ++i) - if (Filter(InVTs[i])) - Result.push_back(InVTs[i]); - return Result; -} - -template -static std::vector -FilterEVTs(const std::vector &InVTs, T Filter) { - std::vector Result; - for (unsigned i = 0, e = InVTs.size(); i != e; ++i) - if (Filter((MVT::SimpleValueType)InVTs[i])) - Result.push_back(InVTs[i]); - return Result; -} +// EEVT::TypeSet Implementation +//===----------------------------------------------------------------------===// -static std::vector -ConvertVTs(const std::vector &InVTs) { - std::vector Result; - for (unsigned i = 0, e = InVTs.size(); i != e; ++i) - Result.push_back(InVTs[i]); - return Result; -} +// FIXME: Remove EEVT::isUnknown! static inline bool isInteger(MVT::SimpleValueType VT) { return EVT(VT).isInteger(); @@ -66,39 +39,361 @@ return EVT(VT).isVector(); } -static bool LHSIsSubsetOfRHS(const std::vector &LHS, - const std::vector &RHS) { - if (LHS.size() > RHS.size()) return false; - for (unsigned i = 0, e = LHS.size(); i != e; ++i) - if (std::find(RHS.begin(), RHS.end(), LHS[i]) == RHS.end()) - return false; - return true; +EEVT::TypeSet::TypeSet(MVT::SimpleValueType VT, TreePattern &TP) { + if (VT == MVT::iAny) + EnforceInteger(TP); + else if (VT == MVT::fAny) + EnforceFloatingPoint(TP); + else if (VT == MVT::vAny) + EnforceVector(TP); + else { + assert((VT < MVT::LAST_VALUETYPE || VT == MVT::iPTR || + VT == MVT::iPTRAny) && "Not a concrete type!"); + TypeVec.push_back(VT); + } +} + + +EEVT::TypeSet::TypeSet(const std::vector &VTList) { + assert(!VTList.empty() && "empty list?"); + TypeVec.append(VTList.begin(), VTList.end()); + + if (!VTList.empty()) + assert(VTList[0] != MVT::iAny && VTList[0] != MVT::vAny && + VTList[0] != MVT::fAny); + + // Remove duplicates. + array_pod_sort(TypeVec.begin(), TypeVec.end()); + TypeVec.erase(std::unique(TypeVec.begin(), TypeVec.end()), TypeVec.end()); +} + + +/// hasIntegerTypes - Return true if this TypeSet contains iAny or an +/// integer value type. +bool EEVT::TypeSet::hasIntegerTypes() const { + for (unsigned i = 0, e = TypeVec.size(); i != e; ++i) + if (isInteger(TypeVec[i])) + return true; + return false; +} + +/// hasFloatingPointTypes - Return true if this TypeSet contains an fAny or +/// a floating point value type. +bool EEVT::TypeSet::hasFloatingPointTypes() const { + for (unsigned i = 0, e = TypeVec.size(); i != e; ++i) + if (isFloatingPoint(TypeVec[i])) + return true; + return false; +} + +/// hasVectorTypes - Return true if this TypeSet contains a vAny or a vector +/// value type. +bool EEVT::TypeSet::hasVectorTypes() const { + for (unsigned i = 0, e = TypeVec.size(); i != e; ++i) + if (isVector(TypeVec[i])) + return true; + return false; +} + + +std::string EEVT::TypeSet::getName() const { + if (TypeVec.empty()) return "isUnknown"; + + std::string Result; + + for (unsigned i = 0, e = TypeVec.size(); i != e; ++i) { + std::string VTName = llvm::getEnumName(TypeVec[i]); + // Strip off MVT:: prefix if present. + if (VTName.substr(0,5) == "MVT::") + VTName = VTName.substr(5); + if (i) Result += ':'; + Result += VTName; + } + + if (TypeVec.size() == 1) + return Result; + return "{" + Result + "}"; +} + +/// MergeInTypeInfo - This merges in type information from the specified +/// argument. If 'this' changes, it returns true. If the two types are +/// contradictory (e.g. merge f32 into i32) then this throws an exception. +bool EEVT::TypeSet::MergeInTypeInfo(const EEVT::TypeSet &InVT, TreePattern &TP){ + if (InVT.isCompletelyUnknown() || *this == InVT) + return false; + + if (isCompletelyUnknown()) { + *this = InVT; + return true; + } + + assert(TypeVec.size() >= 1 && InVT.TypeVec.size() >= 1 && "No unknowns"); + + // Handle the abstract cases, seeing if we can resolve them better. + switch (TypeVec[0]) { + default: break; + case MVT::iPTR: + case MVT::iPTRAny: + if (InVT.hasIntegerTypes()) { + EEVT::TypeSet InCopy(InVT); + InCopy.EnforceInteger(TP); + InCopy.EnforceScalar(TP); + + if (InCopy.isConcrete()) { + // If the RHS has one integer type, upgrade iPTR to i32. + TypeVec[0] = InVT.TypeVec[0]; + return true; + } + + // If the input has multiple scalar integers, this doesn't add any info. + if (!InCopy.isCompletelyUnknown()) + return false; + } + break; + } + + // If the input constraint is iAny/iPTR and this is an integer type list, + // remove non-integer types from the list. + if ((InVT.TypeVec[0] == MVT::iPTR || InVT.TypeVec[0] == MVT::iPTRAny) && + hasIntegerTypes()) { + bool MadeChange = EnforceInteger(TP); + + // If we're merging in iPTR/iPTRAny and the node currently has a list of + // multiple different integer types, replace them with a single iPTR. + if ((InVT.TypeVec[0] == MVT::iPTR || InVT.TypeVec[0] == MVT::iPTRAny) && + TypeVec.size() != 1) { + TypeVec.resize(1); + TypeVec[0] = InVT.TypeVec[0]; + MadeChange = true; + } + + return MadeChange; + } + + // If this is a type list and the RHS is a typelist as well, eliminate entries + // from this list that aren't in the other one. + bool MadeChange = false; + TypeSet InputSet(*this); + + for (unsigned i = 0; i != TypeVec.size(); ++i) { + bool InInVT = false; + for (unsigned j = 0, e = InVT.TypeVec.size(); j != e; ++j) + if (TypeVec[i] == InVT.TypeVec[j]) { + InInVT = true; + break; + } + + if (InInVT) continue; + TypeVec.erase(TypeVec.begin()+i--); + MadeChange = true; + } + + // If we removed all of our types, we have a type contradiction. + if (!TypeVec.empty()) + return MadeChange; + + // FIXME: Really want an SMLoc here! + TP.error("Type inference contradiction found, merging '" + + InVT.getName() + "' into '" + InputSet.getName() + "'"); + return true; // unreachable +} + +/// EnforceInteger - Remove all non-integer types from this set. +bool EEVT::TypeSet::EnforceInteger(TreePattern &TP) { + TypeSet InputSet(*this); + bool MadeChange = false; + + // If we know nothing, then get the full set. + if (TypeVec.empty()) { + *this = TP.getDAGPatterns().getTargetInfo().getLegalValueTypes(); + MadeChange = true; + } + + if (!hasFloatingPointTypes()) + return MadeChange; + + // Filter out all the fp types. + for (unsigned i = 0; i != TypeVec.size(); ++i) + if (isFloatingPoint(TypeVec[i])) + TypeVec.erase(TypeVec.begin()+i--); + + if (TypeVec.empty()) + TP.error("Type inference contradiction found, '" + + InputSet.getName() + "' needs to be integer"); + return MadeChange; } -namespace llvm { -namespace EEVT { -/// isExtIntegerInVTs - Return true if the specified extended value type vector -/// contains iAny or an integer value type. -bool isExtIntegerInVTs(const std::vector &EVTs) { - assert(!EVTs.empty() && "Cannot check for integer in empty ExtVT list!"); - return EVTs[0] == MVT::iAny || !(FilterEVTs(EVTs, isInteger).empty()); -} - -/// isExtFloatingPointInVTs - Return true if the specified extended value type -/// vector contains fAny or a FP value type. -bool isExtFloatingPointInVTs(const std::vector &EVTs) { - assert(!EVTs.empty() && "Cannot check for FP in empty ExtVT list!"); - return EVTs[0] == MVT::fAny || !(FilterEVTs(EVTs, isFloatingPoint).empty()); -} - -/// isExtVectorInVTs - Return true if the specified extended value type -/// vector contains vAny or a vector value type. -bool isExtVectorInVTs(const std::vector &EVTs) { - assert(!EVTs.empty() && "Cannot check for vector in empty ExtVT list!"); - return EVTs[0] == MVT::vAny || !(FilterEVTs(EVTs, isVector).empty()); +/// EnforceFloatingPoint - Remove all integer types from this set. +bool EEVT::TypeSet::EnforceFloatingPoint(TreePattern &TP) { + TypeSet InputSet(*this); + bool MadeChange = false; + + // If we know nothing, then get the full set. + if (TypeVec.empty()) { + *this = TP.getDAGPatterns().getTargetInfo().getLegalValueTypes(); + MadeChange = true; + } + + if (!hasIntegerTypes()) + return MadeChange; + + // Filter out all the fp types. + for (unsigned i = 0; i != TypeVec.size(); ++i) + if (isInteger(TypeVec[i])) + TypeVec.erase(TypeVec.begin()+i--); + + if (TypeVec.empty()) + TP.error("Type inference contradiction found, '" + + InputSet.getName() + "' needs to be floating point"); + return MadeChange; } -} // end namespace EEVT. -} // end namespace llvm. + +/// EnforceScalar - Remove all vector types from this. +bool EEVT::TypeSet::EnforceScalar(TreePattern &TP) { + TypeSet InputSet(*this); + bool MadeChange = false; + + // If we know nothing, then get the full set. + if (TypeVec.empty()) { + *this = TP.getDAGPatterns().getTargetInfo().getLegalValueTypes(); + MadeChange = true; + } + + if (!hasVectorTypes()) + return MadeChange; + + // Filter out all the vector types. + for (unsigned i = 0; i != TypeVec.size(); ++i) + if (isVector(TypeVec[i])) + TypeVec.erase(TypeVec.begin()+i--); + + if (TypeVec.empty()) + TP.error("Type inference contradiction found, '" + + InputSet.getName() + "' needs to be scalar"); + return MadeChange; +} + +/// EnforceVector - Remove all vector types from this. +bool EEVT::TypeSet::EnforceVector(TreePattern &TP) { + TypeSet InputSet(*this); + bool MadeChange = false; + + // If we know nothing, then get the full set. + if (TypeVec.empty()) { + *this = TP.getDAGPatterns().getTargetInfo().getLegalValueTypes(); + MadeChange = true; + } + + // Filter out all the scalar types. + for (unsigned i = 0; i != TypeVec.size(); ++i) + if (!isVector(TypeVec[i])) + TypeVec.erase(TypeVec.begin()+i--); + + if (TypeVec.empty()) + TP.error("Type inference contradiction found, '" + + InputSet.getName() + "' needs to be a vector"); + return MadeChange; +} + + +/// EnforceSmallerThan - 'this' must be a smaller VT than Other. Update +/// this an other based on this information. +bool EEVT::TypeSet::EnforceSmallerThan(EEVT::TypeSet &Other, TreePattern &TP) { + // Both operands must be integer or FP, but we don't care which. + bool MadeChange = false; + + // This code does not currently handle nodes which have multiple types, + // where some types are integer, and some are fp. Assert that this is not + // the case. + assert(!(hasIntegerTypes() && hasFloatingPointTypes()) && + !(Other.hasIntegerTypes() && Other.hasFloatingPointTypes()) && + "SDTCisOpSmallerThanOp does not handle mixed int/fp types!"); + // If one side is known to be integer or known to be FP but the other side has + // no information, get at least the type integrality info in there. + if (hasIntegerTypes()) + MadeChange |= Other.EnforceInteger(TP); + else if (hasFloatingPointTypes()) + MadeChange |= Other.EnforceFloatingPoint(TP); + if (Other.hasIntegerTypes()) + MadeChange |= EnforceInteger(TP); + else if (Other.hasFloatingPointTypes()) + MadeChange |= EnforceFloatingPoint(TP); + + assert(!isCompletelyUnknown() && !Other.isCompletelyUnknown() && + "Should have a type list now"); + + // If one contains vectors but the other doesn't pull vectors out. + if (!hasVectorTypes() && Other.hasVectorTypes()) + MadeChange |= Other.EnforceScalar(TP); + if (hasVectorTypes() && !Other.hasVectorTypes()) + MadeChange |= EnforceScalar(TP); + + // FIXME: This is a bone-headed way to do this. + + // Get the set of legal VTs and filter it based on the known integrality. + const CodeGenTarget &CGT = TP.getDAGPatterns().getTargetInfo(); + TypeSet LegalVTs = CGT.getLegalValueTypes(); + + // TODO: If one or the other side is known to be a specific VT, we could prune + // LegalVTs. + if (hasIntegerTypes()) + LegalVTs.EnforceInteger(TP); + else if (hasFloatingPointTypes()) + LegalVTs.EnforceFloatingPoint(TP); + else + return MadeChange; + + switch (LegalVTs.TypeVec.size()) { + case 0: assert(0 && "No legal VTs?"); + default: // Too many VT's to pick from. + // TODO: If the biggest type in LegalVTs is in this set, we could remove it. + // If one or the other side is known to be a specific VT, we could prune + // LegalVTs. + return MadeChange; + case 1: + // Only one VT of this flavor. Cannot ever satisfy the constraints. + return MergeInTypeInfo(MVT::Other, TP); // throw + case 2: + // If we have exactly two possible types, the little operand must be the + // small one, the big operand should be the big one. This is common with + // float/double for example. + assert(LegalVTs.TypeVec[0] < LegalVTs.TypeVec[1] && "Should be sorted!"); + MadeChange |= MergeInTypeInfo(LegalVTs.TypeVec[0], TP); + MadeChange |= Other.MergeInTypeInfo(LegalVTs.TypeVec[1], TP); + return MadeChange; + } +} + +/// EnforceVectorEltTypeIs - 'this' is now constrainted to be a vector type +/// whose element is VT. +bool EEVT::TypeSet::EnforceVectorEltTypeIs(MVT::SimpleValueType VT, + TreePattern &TP) { + TypeSet InputSet(*this); + bool MadeChange = false; + + // If we know nothing, then get the full set. + if (TypeVec.empty()) { + *this = TP.getDAGPatterns().getTargetInfo().getLegalValueTypes(); + MadeChange = true; + } + + // Filter out all the non-vector types and types which don't have the right + // element type. + for (unsigned i = 0; i != TypeVec.size(); ++i) + if (!isVector(TypeVec[i]) || + EVT(TypeVec[i]).getVectorElementType().getSimpleVT().SimpleTy != VT) { + TypeVec.erase(TypeVec.begin()+i--); + MadeChange = true; + } + + if (TypeVec.empty()) // FIXME: Really want an SMLoc here! + TP.error("Type inference contradiction found, forcing '" + + InputSet.getName() + "' to have a vector element"); + return MadeChange; +} + +//===----------------------------------------------------------------------===// +// Helpers for working with extended types. bool RecordPtrCmp::operator()(const Record *LHS, const Record *RHS) const { return LHS->getID() < RHS->getID(); @@ -208,8 +503,7 @@ R->getValueAsInt("BigOperandNum"); } else if (R->isSubClassOf("SDTCisEltOfVec")) { ConstraintType = SDTCisEltOfVec; - x.SDTCisEltOfVec_Info.OtherOperandNum = - R->getValueAsInt("OtherOpNum"); + x.SDTCisEltOfVec_Info.OtherOperandNum = R->getValueAsInt("OtherOpNum"); } else { errs() << "Unrecognized SDTypeConstraint '" << R->getName() << "'!\n"; exit(1); @@ -255,8 +549,6 @@ itostr(NodeInfo.getNumOperands()) + " operands!"); } - const CodeGenTarget &CGT = TP.getDAGPatterns().getTargetInfo(); - TreePatternNode *NodeToApply = getOperandNum(OperandNo, N, NumResults); switch (ConstraintType) { @@ -264,45 +556,23 @@ case SDTCisVT: // Operand must be a particular type. return NodeToApply->UpdateNodeType(x.SDTCisVT_Info.VT, TP); - case SDTCisPtrTy: { + case SDTCisPtrTy: // Operand must be same as target pointer type. return NodeToApply->UpdateNodeType(MVT::iPTR, TP); - } - case SDTCisInt: { - // If there is only one integer type supported, this must be it. - std::vector IntVTs = - FilterVTs(CGT.getLegalValueTypes(), isInteger); - - // If we found exactly one supported integer type, apply it. - if (IntVTs.size() == 1) - return NodeToApply->UpdateNodeType(IntVTs[0], TP); - return NodeToApply->UpdateNodeType(MVT::iAny, TP); - } - case SDTCisFP: { - // If there is only one FP type supported, this must be it. - std::vector FPVTs = - FilterVTs(CGT.getLegalValueTypes(), isFloatingPoint); - - // If we found exactly one supported FP type, apply it. - if (FPVTs.size() == 1) - return NodeToApply->UpdateNodeType(FPVTs[0], TP); - return NodeToApply->UpdateNodeType(MVT::fAny, TP); - } - case SDTCisVec: { - // If there is only one vector type supported, this must be it. - std::vector VecVTs = - FilterVTs(CGT.getLegalValueTypes(), isVector); - - // If we found exactly one supported vector type, apply it. - if (VecVTs.size() == 1) - return NodeToApply->UpdateNodeType(VecVTs[0], TP); - return NodeToApply->UpdateNodeType(MVT::vAny, TP); - } + case SDTCisInt: + // Require it to be one of the legal integer VTs. + return NodeToApply->getExtType().EnforceInteger(TP); + case SDTCisFP: + // Require it to be one of the legal fp VTs. + return NodeToApply->getExtType().EnforceFloatingPoint(TP); + case SDTCisVec: + // Require it to be one of the legal vector VTs. + return NodeToApply->getExtType().EnforceVector(TP); case SDTCisSameAs: { TreePatternNode *OtherNode = getOperandNum(x.SDTCisSameAs_Info.OtherOperandNum, N, NumResults); - return NodeToApply->UpdateNodeType(OtherNode->getExtTypes(), TP) | - OtherNode->UpdateNodeType(NodeToApply->getExtTypes(), TP); + return NodeToApply->UpdateNodeType(OtherNode->getExtType(), TP) | + OtherNode->UpdateNodeType(NodeToApply->getExtType(), TP); } case SDTCisVTSmallerThanOp: { // The NodeToApply must be a leaf node that is a VT. OtherOperandNum must @@ -321,78 +591,37 @@ getOperandNum(x.SDTCisVTSmallerThanOp_Info.OtherOperandNum, N,NumResults); // It must be integer. - bool MadeChange = OtherNode->UpdateNodeType(MVT::iAny, TP); - - // This code only handles nodes that have one type set. Assert here so - // that we can change this if we ever need to deal with multiple value - // types at this point. - assert(OtherNode->getExtTypes().size() == 1 && "Node has too many types!"); - if (OtherNode->hasTypeSet() && OtherNode->getTypeNum(0) <= VT) + bool MadeChange = OtherNode->getExtType().EnforceInteger(TP); + + // This doesn't try to enforce any information on the OtherNode, it just + // validates it when information is determined. + if (OtherNode->hasTypeSet() && OtherNode->getType() <= VT) OtherNode->UpdateNodeType(MVT::Other, TP); // Throw an error. return MadeChange; } case SDTCisOpSmallerThanOp: { TreePatternNode *BigOperand = getOperandNum(x.SDTCisOpSmallerThanOp_Info.BigOperandNum, N, NumResults); - - // Both operands must be integer or FP, but we don't care which. - bool MadeChange = false; - - // This code does not currently handle nodes which have multiple types, - // where some types are integer, and some are fp. Assert that this is not - // the case. - assert(!(EEVT::isExtIntegerInVTs(NodeToApply->getExtTypes()) && - EEVT::isExtFloatingPointInVTs(NodeToApply->getExtTypes())) && - !(EEVT::isExtIntegerInVTs(BigOperand->getExtTypes()) && - EEVT::isExtFloatingPointInVTs(BigOperand->getExtTypes())) && - "SDTCisOpSmallerThanOp does not handle mixed int/fp types!"); - if (EEVT::isExtIntegerInVTs(NodeToApply->getExtTypes())) - MadeChange |= BigOperand->UpdateNodeType(MVT::iAny, TP); - else if (EEVT::isExtFloatingPointInVTs(NodeToApply->getExtTypes())) - MadeChange |= BigOperand->UpdateNodeType(MVT::fAny, TP); - if (EEVT::isExtIntegerInVTs(BigOperand->getExtTypes())) - MadeChange |= NodeToApply->UpdateNodeType(MVT::iAny, TP); - else if (EEVT::isExtFloatingPointInVTs(BigOperand->getExtTypes())) - MadeChange |= NodeToApply->UpdateNodeType(MVT::fAny, TP); - - std::vector VTs = CGT.getLegalValueTypes(); - - if (EEVT::isExtIntegerInVTs(NodeToApply->getExtTypes())) { - VTs = FilterVTs(VTs, isInteger); - } else if (EEVT::isExtFloatingPointInVTs(NodeToApply->getExtTypes())) { - VTs = FilterVTs(VTs, isFloatingPoint); - } else { - VTs.clear(); - } - - switch (VTs.size()) { - default: // Too many VT's to pick from. - case 0: break; // No info yet. - case 1: - // Only one VT of this flavor. Cannot ever satisfy the constraints. - return NodeToApply->UpdateNodeType(MVT::Other, TP); // throw - case 2: - // If we have exactly two possible types, the little operand must be the - // small one, the big operand should be the big one. Common with - // float/double for example. - assert(VTs[0] < VTs[1] && "Should be sorted!"); - MadeChange |= NodeToApply->UpdateNodeType(VTs[0], TP); - MadeChange |= BigOperand->UpdateNodeType(VTs[1], TP); - break; - } - return MadeChange; + return NodeToApply->getExtType(). + EnforceSmallerThan(BigOperand->getExtType(), TP); } case SDTCisEltOfVec: { - TreePatternNode *OtherOperand = - getOperandNum(x.SDTCisEltOfVec_Info.OtherOperandNum, - N, NumResults); - if (OtherOperand->hasTypeSet()) { - if (!isVector(OtherOperand->getTypeNum(0))) + TreePatternNode *VecOperand = + getOperandNum(x.SDTCisEltOfVec_Info.OtherOperandNum, N, NumResults); + if (VecOperand->hasTypeSet()) { + if (!isVector(VecOperand->getType())) TP.error(N->getOperator()->getName() + " VT operand must be a vector!"); - EVT IVT = OtherOperand->getTypeNum(0); + EVT IVT = VecOperand->getType(); IVT = IVT.getVectorElementType(); return NodeToApply->UpdateNodeType(IVT.getSimpleVT().SimpleTy, TP); } + + if (NodeToApply->hasTypeSet() && VecOperand->getExtType().hasVectorTypes()){ + // Filter vector types out of VecOperand that don't have the right element + // type. + return VecOperand->getExtType(). + EnforceVectorEltTypeIs(NodeToApply->getType(), TP); + } return false; } } @@ -482,133 +711,6 @@ #endif } -/// UpdateNodeType - Set the node type of N to VT if VT contains -/// information. If N already contains a conflicting type, then throw an -/// exception. This returns true if any information was updated. -/// -bool TreePatternNode::UpdateNodeType(const std::vector &ExtVTs, - TreePattern &TP) { - assert(!ExtVTs.empty() && "Cannot update node type with empty type vector!"); - - if (ExtVTs[0] == EEVT::isUnknown || LHSIsSubsetOfRHS(getExtTypes(), ExtVTs)) - return false; - if (isTypeCompletelyUnknown() || LHSIsSubsetOfRHS(ExtVTs, getExtTypes())) { - setTypes(ExtVTs); - return true; - } - - if (getExtTypeNum(0) == MVT::iPTR || getExtTypeNum(0) == MVT::iPTRAny) { - if (ExtVTs[0] == MVT::iPTR || ExtVTs[0] == MVT::iPTRAny || - ExtVTs[0] == MVT::iAny) - return false; - if (EEVT::isExtIntegerInVTs(ExtVTs)) { - std::vector FVTs = FilterEVTs(ExtVTs, isInteger); - if (FVTs.size()) { - setTypes(ExtVTs); - return true; - } - } - } - - // Merge vAny with iAny/fAny. The latter include vector types so keep them - // as the more specific information. - if (ExtVTs[0] == MVT::vAny && - (getExtTypeNum(0) == MVT::iAny || getExtTypeNum(0) == MVT::fAny)) - return false; - if (getExtTypeNum(0) == MVT::vAny && - (ExtVTs[0] == MVT::iAny || ExtVTs[0] == MVT::fAny)) { - setTypes(ExtVTs); - return true; - } - - if (ExtVTs[0] == MVT::iAny && - EEVT::isExtIntegerInVTs(getExtTypes())) { - assert(hasTypeSet() && "should be handled above!"); - std::vector FVTs = FilterEVTs(getExtTypes(), isInteger); - if (getExtTypes() == FVTs) - return false; - setTypes(FVTs); - return true; - } - if ((ExtVTs[0] == MVT::iPTR || ExtVTs[0] == MVT::iPTRAny) && - EEVT::isExtIntegerInVTs(getExtTypes())) { - //assert(hasTypeSet() && "should be handled above!"); - std::vector FVTs = FilterEVTs(getExtTypes(), isInteger); - if (getExtTypes() == FVTs) - return false; - if (FVTs.size()) { - setTypes(FVTs); - return true; - } - } - if (ExtVTs[0] == MVT::fAny && - EEVT::isExtFloatingPointInVTs(getExtTypes())) { - assert(hasTypeSet() && "should be handled above!"); - std::vector FVTs = - FilterEVTs(getExtTypes(), isFloatingPoint); - if (getExtTypes() == FVTs) - return false; - setTypes(FVTs); - return true; - } - if (ExtVTs[0] == MVT::vAny && - EEVT::isExtVectorInVTs(getExtTypes())) { - assert(hasTypeSet() && "should be handled above!"); - std::vector FVTs = FilterEVTs(getExtTypes(), isVector); - if (getExtTypes() == FVTs) - return false; - setTypes(FVTs); - return true; - } - - // If we know this is an int, FP, or vector type, and we are told it is a - // specific one, take the advice. - // - // Similarly, we should probably set the type here to the intersection of - // {iAny|fAny|vAny} and ExtVTs - if ((getExtTypeNum(0) == MVT::iAny && - EEVT::isExtIntegerInVTs(ExtVTs)) || - (getExtTypeNum(0) == MVT::fAny && - EEVT::isExtFloatingPointInVTs(ExtVTs)) || - (getExtTypeNum(0) == MVT::vAny && - EEVT::isExtVectorInVTs(ExtVTs))) { - setTypes(ExtVTs); - return true; - } - if (getExtTypeNum(0) == MVT::iAny && - (ExtVTs[0] == MVT::iPTR || ExtVTs[0] == MVT::iPTRAny)) { - setTypes(ExtVTs); - return true; - } - - if (isLeaf()) { - dump(); - errs() << " "; - TP.error("Type inference contradiction found in node!"); - } else { - TP.error("Type inference contradiction found in node " + - getOperator()->getName() + "!"); - } - return true; // unreachable -} - -static std::string GetTypeName(unsigned char TypeID) { - switch (TypeID) { - case MVT::Other: return "Other"; - case MVT::iAny: return "iAny"; - case MVT::fAny: return "fAny"; - case MVT::vAny: return "vAny"; - case EEVT::isUnknown: return "isUnknown"; - case MVT::iPTR: return "iPTR"; - case MVT::iPTRAny: return "iPTRAny"; - default: - std::string VTName = llvm::getName((MVT::SimpleValueType)TypeID); - // Strip off EVT:: prefix if present. - if (VTName.substr(0,5) == "MVT::") - VTName = VTName.substr(5); - return VTName; - } -} void TreePatternNode::print(raw_ostream &OS) const { @@ -618,10 +720,8 @@ OS << '(' << getOperator()->getName(); } - // FIXME: At some point we should handle printing all the value types for - // nodes that are multiply typed. - if (getExtTypeNum(0) != EEVT::isUnknown) - OS << ':' << GetTypeName(getExtTypeNum(0)); + if (!isTypeCompletelyUnknown()) + OS << ':' << getExtType().getName(); if (!isLeaf()) { if (getNumChildren() != 0) { @@ -657,7 +757,7 @@ bool TreePatternNode::isIsomorphicTo(const TreePatternNode *N, const MultipleUseVarSet &DepVars) const { if (N == this) return true; - if (N->isLeaf() != isLeaf() || getExtTypes() != N->getExtTypes() || + if (N->isLeaf() != isLeaf() || getExtType() != N->getExtType() || getPredicateFns() != N->getPredicateFns() || getTransformFn() != N->getTransformFn()) return false; @@ -695,7 +795,7 @@ New = new TreePatternNode(getOperator(), CChildren); } New->setName(getName()); - New->setTypes(getExtTypes()); + New->setType(getExtType()); New->setPredicateFns(getPredicateFns()); New->setTransformFn(getTransformFn()); return New; @@ -703,7 +803,7 @@ /// RemoveAllTypes - Recursively strip all the types of this tree. void TreePatternNode::RemoveAllTypes() { - removeTypes(); + setType(EEVT::TypeSet()); // Reset to unknown type. if (isLeaf()) return; for (unsigned i = 0, e = getNumChildren(); i != e; ++i) getChild(i)->RemoveAllTypes(); @@ -785,7 +885,7 @@ } FragTree->setName(getName()); - FragTree->UpdateNodeType(getExtTypes(), TP); + FragTree->UpdateNodeType(getExtType(), TP); // Transfer in the old predicates. for (unsigned i = 0, e = getPredicateFns().size(); i != e; ++i) @@ -803,47 +903,40 @@ /// type which should be applied to it. This will infer the type of register /// references from the register file information, for example. /// -static std::vector getImplicitType(Record *R, bool NotRegisters, - TreePattern &TP) { - // Some common return values - std::vector Unknown(1, EEVT::isUnknown); - std::vector Other(1, MVT::Other); - - // Check to see if this is a register or a register class... +static EEVT::TypeSet getImplicitType(Record *R, bool NotRegisters, + TreePattern &TP) { + // Check to see if this is a register or a register class. if (R->isSubClassOf("RegisterClass")) { if (NotRegisters) - return Unknown; - const CodeGenRegisterClass &RC = - TP.getDAGPatterns().getTargetInfo().getRegisterClass(R); - return ConvertVTs(RC.getValueTypes()); + return EEVT::TypeSet(); // Unknown. + const CodeGenTarget &T = TP.getDAGPatterns().getTargetInfo(); + return EEVT::TypeSet(T.getRegisterClass(R).getValueTypes()); } else if (R->isSubClassOf("PatFrag")) { // Pattern fragment types will be resolved when they are inlined. - return Unknown; + return EEVT::TypeSet(); // Unknown. } else if (R->isSubClassOf("Register")) { if (NotRegisters) - return Unknown; + return EEVT::TypeSet(); // Unknown. const CodeGenTarget &T = TP.getDAGPatterns().getTargetInfo(); - return T.getRegisterVTs(R); + return EEVT::TypeSet(T.getRegisterVTs(R)); } else if (R->isSubClassOf("ValueType") || R->isSubClassOf("CondCode")) { // Using a VTSDNode or CondCodeSDNode. - return Other; + return EEVT::TypeSet(MVT::Other, TP); } else if (R->isSubClassOf("ComplexPattern")) { if (NotRegisters) - return Unknown; - std::vector - ComplexPat(1, TP.getDAGPatterns().getComplexPattern(R).getValueType()); - return ComplexPat; + return EEVT::TypeSet(); // Unknown. + return EEVT::TypeSet(TP.getDAGPatterns().getComplexPattern(R).getValueType(), + TP); } else if (R->isSubClassOf("PointerLikeRegClass")) { - Other[0] = MVT::iPTR; - return Other; + return EEVT::TypeSet(MVT::iPTR, TP); } else if (R->getName() == "node" || R->getName() == "srcvalue" || R->getName() == "zero_reg") { // Placeholder. - return Unknown; + return EEVT::TypeSet(); // Unknown. } TP.error("Unknown node flavor used in pattern: " + R->getName()); - return Other; + return EEVT::TypeSet(MVT::Other, TP); } @@ -927,40 +1020,33 @@ if (IntInit *II = dynamic_cast(getLeafValue())) { // Int inits are always integers. :) - bool MadeChange = UpdateNodeType(MVT::iAny, TP); + bool MadeChange = Type.EnforceInteger(TP); - if (hasTypeSet()) { - // At some point, it may make sense for this tree pattern to have - // multiple types. Assert here that it does not, so we revisit this - // code when appropriate. - assert(getExtTypes().size() >= 1 && "TreePattern doesn't have a type!"); - MVT::SimpleValueType VT = getTypeNum(0); - for (unsigned i = 1, e = getExtTypes().size(); i != e; ++i) - assert(getTypeNum(i) == VT && "TreePattern has too many types!"); - - VT = getTypeNum(0); - if (VT != MVT::iPTR && VT != MVT::iPTRAny) { - unsigned Size = EVT(VT).getSizeInBits(); - // Make sure that the value is representable for this type. - if (Size < 32) { - int Val = (II->getValue() << (32-Size)) >> (32-Size); - if (Val != II->getValue()) { - // If sign-extended doesn't fit, does it fit as unsigned? - unsigned ValueMask; - unsigned UnsignedVal; - ValueMask = unsigned(~uint32_t(0UL) >> (32-Size)); - UnsignedVal = unsigned(II->getValue()); - - if ((ValueMask & UnsignedVal) != UnsignedVal) { - TP.error("Integer value '" + itostr(II->getValue())+ - "' is out of range for type '" + - getEnumName(getTypeNum(0)) + "'!"); - } - } - } - } - } + if (!hasTypeSet()) + return MadeChange; + + MVT::SimpleValueType VT = getType(); + if (VT == MVT::iPTR || VT == MVT::iPTRAny) + return MadeChange; + + unsigned Size = EVT(VT).getSizeInBits(); + // Make sure that the value is representable for this type. + if (Size >= 32) return MadeChange; + int Val = (II->getValue() << (32-Size)) >> (32-Size); + if (Val == II->getValue()) return MadeChange; + + // If sign-extended doesn't fit, does it fit as unsigned? + unsigned ValueMask; + unsigned UnsignedVal; + ValueMask = unsigned(~uint32_t(0UL) >> (32-Size)); + UnsignedVal = unsigned(II->getValue()); + + if ((ValueMask & UnsignedVal) == UnsignedVal) + return MadeChange; + + TP.error("Integer value '" + itostr(II->getValue())+ + "' is out of range for type '" + getEnumName(getType()) + "'!"); return MadeChange; } return false; @@ -976,11 +1062,9 @@ MadeChange |= getChild(NC-1)->ApplyTypeConstraints(TP, NotRegisters); // Types of operands must match. - MadeChange |= getChild(i)->UpdateNodeType(getChild(NC-1)->getExtTypes(), - TP); - MadeChange |= getChild(NC-1)->UpdateNodeType(getChild(i)->getExtTypes(), - TP); - MadeChange |= UpdateNodeType(MVT::isVoid, TP); + MadeChange |=getChild(i)->UpdateNodeType(getChild(NC-1)->getExtType(),TP); + MadeChange |=getChild(NC-1)->UpdateNodeType(getChild(i)->getExtType(),TP); + MadeChange |=UpdateNodeType(MVT::isVoid, TP); } return MadeChange; } @@ -998,6 +1082,15 @@ bool MadeChange = false; MadeChange |= getChild(0)->ApplyTypeConstraints(TP, NotRegisters); MadeChange |= getChild(1)->ApplyTypeConstraints(TP, NotRegisters); + + // child #1 of COPY_TO_REGCLASS should be a register class. We don't care + // what type it gets, so if it didn't get a concrete type just give it the + // first viable type from the reg class. + if (!getChild(1)->hasTypeSet() && + !getChild(1)->getExtType().isCompletelyUnknown()) { + MVT::SimpleValueType RCVT = getChild(1)->getExtType().getTypeList()[0]; + MadeChange |= getChild(1)->UpdateNodeType(RCVT, TP); + } return MadeChange; } @@ -1058,22 +1151,26 @@ Record *ResultNode = Inst.getResult(0); if (ResultNode->isSubClassOf("PointerLikeRegClass")) { - std::vector VT; - VT.push_back(MVT::iPTR); - MadeChange = UpdateNodeType(VT, TP); + MadeChange = UpdateNodeType(MVT::iPTR, TP); } else if (ResultNode->getName() == "unknown") { - std::vector VT; - VT.push_back(EEVT::isUnknown); - MadeChange = UpdateNodeType(VT, TP); + // Nothing to do. } else { assert(ResultNode->isSubClassOf("RegisterClass") && "Operands should be register classes!"); const CodeGenRegisterClass &RC = CDP.getTargetInfo().getRegisterClass(ResultNode); - MadeChange = UpdateNodeType(ConvertVTs(RC.getValueTypes()), TP); + MadeChange = UpdateNodeType(RC.getValueTypes(), TP); } } + + // If this is an INSERT_SUBREG, constrain the source and destination VTs to + // be the same. + if (getOperator()->getName() == "INSERT_SUBREG") { + MadeChange |= UpdateNodeType(getChild(0)->getExtType(), TP); + MadeChange |= getChild(0)->UpdateNodeType(getExtType(), TP); + } + unsigned ChildNo = 0; for (unsigned i = 0, e = Inst.getNumOperands(); i != e; ++i) { @@ -1097,14 +1194,14 @@ if (OperandNode->isSubClassOf("RegisterClass")) { const CodeGenRegisterClass &RC = CDP.getTargetInfo().getRegisterClass(OperandNode); - MadeChange |= Child->UpdateNodeType(ConvertVTs(RC.getValueTypes()), TP); + MadeChange |= Child->UpdateNodeType(RC.getValueTypes(), TP); } else if (OperandNode->isSubClassOf("Operand")) { VT = getValueType(OperandNode->getValueAsDef("Type")); MadeChange |= Child->UpdateNodeType(VT, TP); } else if (OperandNode->isSubClassOf("PointerLikeRegClass")) { MadeChange |= Child->UpdateNodeType(MVT::iPTR, TP); } else if (OperandNode->getName() == "unknown") { - MadeChange |= Child->UpdateNodeType(EEVT::isUnknown, TP); + // Nothing to do. } else { assert(0 && "Unknown operand type!"); abort(); @@ -1126,15 +1223,20 @@ TP.error("Node transform '" + getOperator()->getName() + "' requires one operand!"); + bool MadeChange = getChild(0)->ApplyTypeConstraints(TP, NotRegisters); + + // If either the output or input of the xform does not have exact // type info. We assume they must be the same. Otherwise, it is perfectly // legal to transform from one type to a completely different type. +#if 0 if (!hasTypeSet() || !getChild(0)->hasTypeSet()) { - bool MadeChange = UpdateNodeType(getChild(0)->getExtTypes(), TP); - MadeChange |= getChild(0)->UpdateNodeType(getExtTypes(), TP); + bool MadeChange = UpdateNodeType(getChild(0)->getExtType(), TP); + MadeChange |= getChild(0)->UpdateNodeType(getExtType(), TP); return MadeChange; } - return false; +#endif + return MadeChange; } /// OnlyOnRHSOfCommutative - Return true if this value is only allowed on the @@ -1194,9 +1296,9 @@ TreePattern::TreePattern(Record *TheRec, ListInit *RawPat, bool isInput, CodeGenDAGPatterns &cdp) : TheRecord(TheRec), CDP(cdp){ - isInputPattern = isInput; - for (unsigned i = 0, e = RawPat->getSize(); i != e; ++i) - Trees.push_back(ParseTreePattern((DagInit*)RawPat->getElement(i))); + isInputPattern = isInput; + for (unsigned i = 0, e = RawPat->getSize(); i != e; ++i) + Trees.push_back(ParseTreePattern((DagInit*)RawPat->getElement(i))); } TreePattern::TreePattern(Record *TheRec, DagInit *Pat, bool isInput, @@ -1211,13 +1313,24 @@ Trees.push_back(Pat); } - - void TreePattern::error(const std::string &Msg) const { dump(); throw TGError(TheRecord->getLoc(), "In " + TheRecord->getName() + ": " + Msg); } +void TreePattern::ComputeNamedNodes() { + for (unsigned i = 0, e = Trees.size(); i != e; ++i) + ComputeNamedNodes(Trees[i]); +} + +void TreePattern::ComputeNamedNodes(TreePatternNode *N) { + if (!N->getName().empty()) + NamedNodes[N->getName()].push_back(N); + + for (unsigned i = 0, e = N->getNumChildren(); i != e; ++i) + ComputeNamedNodes(N->getChild(i)); +} + TreePatternNode *TreePattern::ParseTreePattern(DagInit *Dag) { DefInit *OpDef = dynamic_cast(Dag->getOperator()); if (!OpDef) error("Pattern has unexpected operator type!"); @@ -1373,12 +1486,58 @@ /// InferAllTypes - Infer/propagate as many types throughout the expression /// patterns as possible. Return true if all types are inferred, false /// otherwise. Throw an exception if a type contradiction is found. -bool TreePattern::InferAllTypes() { +bool TreePattern:: +InferAllTypes(const StringMap > *InNamedTypes) { + if (NamedNodes.empty()) + ComputeNamedNodes(); + bool MadeChange = true; while (MadeChange) { MadeChange = false; for (unsigned i = 0, e = Trees.size(); i != e; ++i) MadeChange |= Trees[i]->ApplyTypeConstraints(*this, false); + + // If there are constraints on our named nodes, apply them. + for (StringMap >::iterator + I = NamedNodes.begin(), E = NamedNodes.end(); I != E; ++I) { + SmallVectorImpl &Nodes = I->second; + + // If we have input named node types, propagate their types to the named + // values here. + if (InNamedTypes) { + // FIXME: Should be error? + assert(InNamedTypes->count(I->getKey()) && + "Named node in output pattern but not input pattern?"); + + const SmallVectorImpl &InNodes = + InNamedTypes->find(I->getKey())->second; + + // The input types should be fully resolved by now. + for (unsigned i = 0, e = Nodes.size(); i != e; ++i) { + // If this node is a register class, and it is the root of the pattern + // then we're mapping something onto an input register. We allow + // changing the type of the input register in this case. This allows + // us to match things like: + // def : Pat<(v1i64 (bitconvert(v2i32 DPR:$src))), (v1i64 DPR:$src)>; + if (Nodes[i] == Trees[0] && Nodes[i]->isLeaf()) { + DefInit *DI = dynamic_cast(Nodes[i]->getLeafValue()); + if (DI && DI->getDef()->isSubClassOf("RegisterClass")) + continue; + } + + MadeChange |=Nodes[i]->UpdateNodeType(InNodes[0]->getExtType(),*this); + } + } + + // If there are multiple nodes with the same name, they must all have the + // same type. + if (I->second.size() > 1) { + for (unsigned i = 0, e = Nodes.size()-1; i != e; ++i) { + MadeChange |=Nodes[i]->UpdateNodeType(Nodes[i+1]->getExtType(),*this); + MadeChange |=Nodes[i+1]->UpdateNodeType(Nodes[i]->getExtType(),*this); + } + } + } } bool HasUnresolvedTypes = false; @@ -1673,7 +1832,7 @@ // Ensure that the inputs agree if we've already seen this input. if (Rec != SlotRec) I->error("All $" + Pat->getName() + " inputs must agree with each other"); - if (Slot->getExtTypes() != Pat->getExtTypes()) + if (Slot->getExtType() != Pat->getExtType()) I->error("All $" + Pat->getName() + " inputs must agree with each other"); return true; } @@ -1712,7 +1871,7 @@ // If this is not a set, verify that the children nodes are not void typed, // and recurse. for (unsigned i = 0, e = Pat->getNumChildren(); i != e; ++i) { - if (Pat->getChild(i)->getExtTypeNum(0) == MVT::isVoid) + if (Pat->getChild(i)->getType() == MVT::isVoid) I->error("Cannot have void nodes inside of patterns!"); FindPatternInputsAndOutputs(I, Pat->getChild(i), InstInputs, InstResults, InstImpInputs, InstImpResults); @@ -1960,7 +2119,7 @@ // fill in the InstResults map. for (unsigned j = 0, e = I->getNumTrees(); j != e; ++j) { TreePatternNode *Pat = I->getTree(j); - if (Pat->getExtTypeNum(0) != MVT::isVoid) + if (!Pat->hasTypeSet() || Pat->getType() != MVT::isVoid) I->error("Top-level forms in instruction pattern should have" " void types"); @@ -2072,7 +2231,7 @@ new TreePatternNode(I->getRecord(), ResultNodeOperands); // Copy fully inferred output node type to instruction result pattern. if (NumResults > 0) - ResultPattern->setTypes(Res0Node->getExtTypes()); + ResultPattern->setType(Res0Node->getExtType()); // Create and insert the instruction. // FIXME: InstImpResults and InstImpInputs should not be part of @@ -2084,7 +2243,7 @@ // constructed result is correct. This depends on the instruction already // being inserted into the Instructions map. TreePattern Temp(I->getRecord(), ResultPattern, false, *this); - Temp.InferAllTypes(); + Temp.InferAllTypes(&I->getNamedNodesMap()); DAGInstruction &TheInsertedInst = Instructions.find(I->getRecord())->second; TheInsertedInst.setResultPattern(Temp.getOnlyTree()); @@ -2133,7 +2292,7 @@ // If this is the first instance of the name, remember the node. if (Rec.second++ == 0) Rec.first = P; - else if (Rec.first->getExtTypes() != P->getExtTypes()) + else if (Rec.first->getType() != P->getType()) PatternTop->error("repetition of value: $" + P->getName() + " where different uses have different types!"); } @@ -2220,6 +2379,30 @@ } } +/// Given a pattern result with an unresolved type, see if we can find one +/// instruction with an unresolved result type. Force this result type to an +/// arbitrary element if it's possible types to converge results. +static bool ForceArbitraryInstResultType(TreePatternNode *N, TreePattern &TP) { + if (N->isLeaf()) + return false; + + // Analyze children. + for (unsigned i = 0, e = N->getNumChildren(); i != e; ++i) + if (ForceArbitraryInstResultType(N->getChild(i), TP)) + return true; + + if (!N->getOperator()->isSubClassOf("Instruction")) + return false; + + // If this type is already concrete or completely unknown we can't do + // anything. + if (N->getExtType().isCompletelyUnknown() || N->getExtType().isConcrete()) + return false; + + // Otherwise, force its type to the first possibility (an arbitrary choice). + return N->getExtType().MergeInTypeInfo(N->getExtType().getTypeList()[0], TP); +} + void CodeGenDAGPatterns::ParsePatterns() { std::vector Patterns = Records.getAllDerivedDefinitions("Pattern"); @@ -2278,28 +2461,47 @@ do { // Infer as many types as possible. If we cannot infer all of them, we // can never do anything with this pattern: report it to the user. - InferredAllPatternTypes = Pattern->InferAllTypes(); + InferredAllPatternTypes = + Pattern->InferAllTypes(&Pattern->getNamedNodesMap()); // Infer as many types as possible. If we cannot infer all of them, we // can never do anything with this pattern: report it to the user. - InferredAllResultTypes = Result->InferAllTypes(); + InferredAllResultTypes = + Result->InferAllTypes(&Pattern->getNamedNodesMap()); // Apply the type of the result to the source pattern. This helps us // resolve cases where the input type is known to be a pointer type (which // is considered resolved), but the result knows it needs to be 32- or // 64-bits. Infer the other way for good measure. IterateInference = Pattern->getTree(0)-> - UpdateNodeType(Result->getTree(0)->getExtTypes(), *Result); + UpdateNodeType(Result->getTree(0)->getExtType(), *Result); IterateInference |= Result->getTree(0)-> - UpdateNodeType(Pattern->getTree(0)->getExtTypes(), *Result); + UpdateNodeType(Pattern->getTree(0)->getExtType(), *Result); + + // If our iteration has converged and the input pattern's types are fully + // resolved but the result pattern is not fully resolved, we may have a + // situation where we have two instructions in the result pattern and + // the instructions require a common register class, but don't care about + // what actual MVT is used. This is actually a bug in our modelling: + // output patterns should have register classes, not MVTs. + // + // In any case, to handle this, we just go through and disambiguate some + // arbitrary types to the result pattern's nodes. + if (!IterateInference && InferredAllPatternTypes && + !InferredAllResultTypes) + IterateInference = ForceArbitraryInstResultType(Result->getTree(0), + *Result); + } while (IterateInference); // Verify that we inferred enough types that we can do something with the // pattern and result. If these fire the user has to add type casts. if (!InferredAllPatternTypes) Pattern->error("Could not infer all types in pattern!"); - if (!InferredAllResultTypes) + if (!InferredAllResultTypes) { + Pattern->dump(); Result->error("Could not infer all types in pattern result!"); + } // Validate that the input pattern is correct. std::map InstInputs; @@ -2328,7 +2530,7 @@ if (!DstPattern->isLeaf()) DstPattern = new TreePatternNode(DstPattern->getOperator(), ResultNodeOperands); - DstPattern->setTypes(Result->getOnlyTree()->getExtTypes()); + DstPattern->setType(Result->getOnlyTree()->getExtType()); TreePattern Temp(Result->getRecord(), DstPattern, false, *this); Temp.InferAllTypes(); @@ -2378,7 +2580,7 @@ R->setName(Orig->getName()); R->setPredicateFns(Orig->getPredicateFns()); R->setTransformFn(Orig->getTransformFn()); - R->setTypes(Orig->getExtTypes()); + R->setType(Orig->getExtType()); // If this pattern cannot match, do not include it as a variant. std::string ErrString; Modified: llvm/trunk/utils/TableGen/CodeGenDAGPatterns.h URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/utils/TableGen/CodeGenDAGPatterns.h?rev=98534&r1=98533&r2=98534&view=diff ============================================================================== --- llvm/trunk/utils/TableGen/CodeGenDAGPatterns.h (original) +++ llvm/trunk/utils/TableGen/CodeGenDAGPatterns.h Mon Mar 15 01:00:16 2010 @@ -21,6 +21,8 @@ #include "CodeGenTarget.h" #include "CodeGenIntrinsics.h" +#include "llvm/ADT/SmallVector.h" +#include "llvm/ADT/StringMap.h" namespace llvm { class Record; @@ -40,20 +42,99 @@ /// value is needed. namespace EEVT { enum DAGISelGenValueType { + // FIXME: Remove EEVT::isUnknown! isUnknown = MVT::LAST_VALUETYPE }; - - /// isExtIntegerInVTs - Return true if the specified extended value type - /// vector contains iAny or an integer value type. - bool isExtIntegerInVTs(const std::vector &EVTs); - - /// isExtFloatingPointInVTs - Return true if the specified extended value - /// type vector contains fAny or a FP value type. - bool isExtFloatingPointInVTs(const std::vector &EVTs); - - /// isExtVectorinVTs - Return true if the specified extended value type - /// vector contains vAny or a vector value type. - bool isExtVectorInVTs(const std::vector &EVTs); + + /// TypeSet - This is either empty if it's completely unknown, or holds a set + /// of types. It is used during type inference because register classes can + /// have multiple possible types and we don't know which one they get until + /// type inference is complete. + /// + /// TypeSet can have three states: + /// Vector is empty: The type is completely unknown, it can be any valid + /// target type. + /// Vector has multiple constrained types: (e.g. v4i32 + v4f32) it is one + /// of those types only. + /// Vector has one concrete type: The type is completely known. + /// + class TypeSet { + SmallVector TypeVec; + public: + TypeSet() {} + TypeSet(MVT::SimpleValueType VT, TreePattern &TP); + TypeSet(const std::vector &VTList); + + bool isCompletelyUnknown() const { return TypeVec.empty(); } + + bool isConcrete() const { + if (TypeVec.size() != 1) return false; + unsigned char T = TypeVec[0]; (void)T; + assert(T < MVT::LAST_VALUETYPE || T == MVT::iPTR || T == MVT::iPTRAny); + return true; + } + + MVT::SimpleValueType getConcrete() const { + assert(isConcrete() && "Type isn't concrete yet"); + return (MVT::SimpleValueType)TypeVec[0]; + } + + bool isDynamicallyResolved() const { + return getConcrete() == MVT::iPTR || getConcrete() == MVT::iPTRAny; + } + + const SmallVectorImpl &getTypeList() const { + assert(!TypeVec.empty() && "Not a type list!"); + return TypeVec; + } + + /// hasIntegerTypes - Return true if this TypeSet contains any integer value + /// types. + bool hasIntegerTypes() const; + + /// hasFloatingPointTypes - Return true if this TypeSet contains an fAny or + /// a floating point value type. + bool hasFloatingPointTypes() const; + + /// hasVectorTypes - Return true if this TypeSet contains a vector value + /// type. + bool hasVectorTypes() const; + + /// getName() - Return this TypeSet as a string. + std::string getName() const; + + /// MergeInTypeInfo - This merges in type information from the specified + /// argument. If 'this' changes, it returns true. If the two types are + /// contradictory (e.g. merge f32 into i32) then this throws an exception. + bool MergeInTypeInfo(const EEVT::TypeSet &InVT, TreePattern &TP); + + bool MergeInTypeInfo(MVT::SimpleValueType InVT, TreePattern &TP) { + return MergeInTypeInfo(EEVT::TypeSet(InVT, TP), TP); + } + + /// Force this type list to only contain integer types. + bool EnforceInteger(TreePattern &TP); + + /// Force this type list to only contain floating point types. + bool EnforceFloatingPoint(TreePattern &TP); + + /// EnforceScalar - Remove all vector types from this type list. + bool EnforceScalar(TreePattern &TP); + + /// EnforceVector - Remove all non-vector types from this type list. + bool EnforceVector(TreePattern &TP); + + /// EnforceSmallerThan - 'this' must be a smaller VT than Other. Update + /// this an other based on this information. + bool EnforceSmallerThan(EEVT::TypeSet &Other, TreePattern &TP); + + /// EnforceVectorEltTypeIs - 'this' is now constrainted to be a vector type + /// whose element is VT. + bool EnforceVectorEltTypeIs(MVT::SimpleValueType VT, TreePattern &TP); + + bool operator!=(const TypeSet &RHS) const { return TypeVec != RHS.TypeVec; } + bool operator==(const TypeSet &RHS) const { return TypeVec == RHS.TypeVec; } + }; } /// Set type used to track multiply used variables in patterns @@ -72,7 +153,7 @@ union { // The discriminated union. struct { - unsigned char VT; + MVT::SimpleValueType VT; } SDTCisVT_Info; struct { unsigned OtherOperandNum; @@ -150,10 +231,10 @@ /// patterns), and as such should be ref counted. We currently just leak all /// TreePatternNode objects! class TreePatternNode { - /// The inferred type for this node, or EEVT::isUnknown if it hasn't - /// been determined yet. This is a std::vector because during inference - /// there may be multiple possible types. - std::vector Types; + /// The type of this node. Before and during type inference, this may be a + /// set of possible types. After (successful) type inference, this is a + /// single type. + EEVT::TypeSet Type; /// Operator - The Record for the operator if this is an interior node (not /// a leaf). @@ -178,11 +259,9 @@ std::vector Children; public: TreePatternNode(Record *Op, const std::vector &Ch) - : Types(), Operator(Op), Val(0), TransformFn(0), - Children(Ch) { Types.push_back(EEVT::isUnknown); } + : Operator(Op), Val(0), TransformFn(0), Children(Ch) { } TreePatternNode(Init *val) // leaf ctor - : Types(), Operator(0), Val(val), TransformFn(0) { - Types.push_back(EEVT::isUnknown); + : Operator(0), Val(val), TransformFn(0) { } ~TreePatternNode(); @@ -190,28 +269,16 @@ void setName(const std::string &N) { Name = N; } bool isLeaf() const { return Val != 0; } - bool hasTypeSet() const { - return (Types[0] < MVT::LAST_VALUETYPE) || (Types[0] == MVT::iPTR) || - (Types[0] == MVT::iPTRAny); - } - bool isTypeCompletelyUnknown() const { - return Types[0] == EEVT::isUnknown; - } - bool isTypeDynamicallyResolved() const { - return (Types[0] == MVT::iPTR) || (Types[0] == MVT::iPTRAny); - } - MVT::SimpleValueType getTypeNum(unsigned Num) const { - assert(hasTypeSet() && "Doesn't have a type yet!"); - assert(Types.size() > Num && "Type num out of range!"); - return (MVT::SimpleValueType)Types[Num]; - } - unsigned char getExtTypeNum(unsigned Num) const { - assert(Types.size() > Num && "Extended type num out of range!"); - return Types[Num]; - } - const std::vector &getExtTypes() const { return Types; } - void setTypes(const std::vector &T) { Types = T; } - void removeTypes() { Types = std::vector(1, EEVT::isUnknown); } + + // Type accessors. + MVT::SimpleValueType getType() const { return Type.getConcrete(); } + const EEVT::TypeSet &getExtType() const { return Type; } + EEVT::TypeSet &getExtType() { return Type; } + void setType(const EEVT::TypeSet &T) { Type = T; } + + bool hasTypeSet() const { return Type.isConcrete(); } + bool isTypeCompletelyUnknown() const { return Type.isCompletelyUnknown(); } + bool isTypeDynamicallyResolved() const { return Type.isDynamicallyResolved();} Init *getLeafValue() const { assert(isLeaf()); return Val; } Record *getOperator() const { assert(!isLeaf()); return Operator; } @@ -304,17 +371,18 @@ /// information. If N already contains a conflicting type, then throw an /// exception. This returns true if any information was updated. /// - bool UpdateNodeType(const std::vector &ExtVTs, - TreePattern &TP); - bool UpdateNodeType(unsigned char ExtVT, TreePattern &TP) { - std::vector ExtVTs(1, ExtVT); - return UpdateNodeType(ExtVTs, TP); + bool UpdateNodeType(const EEVT::TypeSet &InTy, TreePattern &TP) { + return Type.MergeInTypeInfo(InTy, TP); + } + + bool UpdateNodeType(MVT::SimpleValueType InTy, TreePattern &TP) { + return Type.MergeInTypeInfo(EEVT::TypeSet(InTy, TP), TP); } /// ContainsUnresolvedType - Return true if this tree contains any /// unresolved types. bool ContainsUnresolvedType() const { - if (!hasTypeSet() && !isTypeDynamicallyResolved()) return true; + if (!hasTypeSet()) return true; for (unsigned i = 0, e = getNumChildren(); i != e; ++i) if (getChild(i)->ContainsUnresolvedType()) return true; return false; @@ -340,6 +408,10 @@ /// std::vector Trees; + /// NamedNodes - This is all of the nodes that have names in the trees in this + /// pattern. + StringMap > NamedNodes; + /// TheRecord - The actual TableGen record corresponding to this pattern. /// Record *TheRecord; @@ -375,6 +447,12 @@ assert(Trees.size() == 1 && "Doesn't have exactly one pattern!"); return Trees[0]; } + + const StringMap > &getNamedNodesMap() { + if (NamedNodes.empty()) + ComputeNamedNodes(); + return NamedNodes; + } /// getRecord - Return the actual TableGen record corresponding to this /// pattern. @@ -401,7 +479,8 @@ /// InferAllTypes - Infer/propagate as many types throughout the expression /// patterns as possible. Return true if all types are inferred, false /// otherwise. Throw an exception if a type contradiction is found. - bool InferAllTypes(); + bool InferAllTypes(const StringMap > + *NamedTypes=0); /// error - Throw an exception, prefixing it with information about this /// pattern. @@ -412,6 +491,8 @@ private: TreePatternNode *ParseTreePattern(DagInit *DI); + void ComputeNamedNodes(); + void ComputeNamedNodes(TreePatternNode *N); }; /// DAGDefaultOperand - One of these is created for each PredicateOperand Modified: llvm/trunk/utils/TableGen/CodeGenTarget.cpp URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/utils/TableGen/CodeGenTarget.cpp?rev=98534&r1=98533&r2=98534&view=diff ============================================================================== --- llvm/trunk/utils/TableGen/CodeGenTarget.cpp (original) +++ llvm/trunk/utils/TableGen/CodeGenTarget.cpp Mon Mar 15 01:00:16 2010 @@ -184,16 +184,16 @@ RegisterClasses.assign(RegClasses.begin(), RegClasses.end()); } -std::vector CodeGenTarget::getRegisterVTs(Record *R) const { - std::vector Result; +std::vector CodeGenTarget:: +getRegisterVTs(Record *R) const { + std::vector Result; const std::vector &RCs = getRegisterClasses(); for (unsigned i = 0, e = RCs.size(); i != e; ++i) { const CodeGenRegisterClass &RC = RegisterClasses[i]; for (unsigned ei = 0, ee = RC.Elements.size(); ei != ee; ++ei) { if (R == RC.Elements[ei]) { const std::vector &InVTs = RC.getValueTypes(); - for (unsigned i = 0, e = InVTs.size(); i != e; ++i) - Result.push_back(InVTs[i]); + Result.insert(Result.end(), InVTs.begin(), InVTs.end()); } } } Modified: llvm/trunk/utils/TableGen/CodeGenTarget.h URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/utils/TableGen/CodeGenTarget.h?rev=98534&r1=98533&r2=98534&view=diff ============================================================================== --- llvm/trunk/utils/TableGen/CodeGenTarget.h (original) +++ llvm/trunk/utils/TableGen/CodeGenTarget.h Mon Mar 15 01:00:16 2010 @@ -167,7 +167,7 @@ /// getRegisterVTs - Find the union of all possible SimpleValueTypes for the /// specified physical register. - std::vector getRegisterVTs(Record *R) const; + std::vector getRegisterVTs(Record *R) const; const std::vector &getLegalValueTypes() const { if (LegalValueTypes.empty()) ReadLegalValueTypes(); Modified: llvm/trunk/utils/TableGen/DAGISelEmitter.cpp URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/utils/TableGen/DAGISelEmitter.cpp?rev=98534&r1=98533&r2=98534&view=diff ============================================================================== --- llvm/trunk/utils/TableGen/DAGISelEmitter.cpp (original) +++ llvm/trunk/utils/TableGen/DAGISelEmitter.cpp Mon Mar 15 01:00:16 2010 @@ -25,13 +25,7 @@ /// patterns before small ones. This is used to determine the size of a /// pattern. static unsigned getPatternSize(TreePatternNode *P, CodeGenDAGPatterns &CGP) { - assert((EEVT::isExtIntegerInVTs(P->getExtTypes()) || - EEVT::isExtFloatingPointInVTs(P->getExtTypes()) || - P->getExtTypeNum(0) == MVT::isVoid || - P->getExtTypeNum(0) == MVT::Flag || - P->getExtTypeNum(0) == MVT::iPTR || - P->getExtTypeNum(0) == MVT::iPTRAny) && - "Not a valid pattern node to size!"); + assert(P->hasTypeSet() && "Not a valid pattern node to size!"); unsigned Size = 3; // The node itself. // If the root node is a ConstantSDNode, increases its size. // e.g. (set R32:$dst, 0). @@ -55,7 +49,7 @@ // Count children in the count if they are also nodes. for (unsigned i = 0, e = P->getNumChildren(); i != e; ++i) { TreePatternNode *Child = P->getChild(i); - if (!Child->isLeaf() && Child->getExtTypeNum(0) != MVT::Other) + if (!Child->isLeaf() && Child->getType() != MVT::Other) Size += getPatternSize(Child, CGP); else if (Child->isLeaf()) { if (dynamic_cast(Child->getLeafValue())) Modified: llvm/trunk/utils/TableGen/DAGISelMatcherGen.cpp URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/utils/TableGen/DAGISelMatcherGen.cpp?rev=98534&r1=98533&r2=98534&view=diff ============================================================================== --- llvm/trunk/utils/TableGen/DAGISelMatcherGen.cpp (original) +++ llvm/trunk/utils/TableGen/DAGISelMatcherGen.cpp Mon Mar 15 01:00:16 2010 @@ -408,11 +408,11 @@ // If N and NodeNoTypes don't agree on a type, then this is a case where we // need to do a type check. Emit the check, apply the tyep to NodeNoTypes and // reinfer any correlated types. - unsigned NodeType = EEVT::isUnknown; - if (NodeNoTypes->getExtTypes() != N->getExtTypes()) { - NodeType = N->getTypeNum(0); - NodeNoTypes->setTypes(N->getExtTypes()); + bool DoTypeCheck = false; + if (NodeNoTypes->getExtType() != N->getExtType()) { + NodeNoTypes->setType(N->getExtType()); InferPossibleTypes(); + DoTypeCheck = true; } // If this node has a name associated with it, capture it in VariableMap. If @@ -442,8 +442,8 @@ for (unsigned i = 0, e = N->getPredicateFns().size(); i != e; ++i) AddMatcher(new CheckPredicateMatcher(N->getPredicateFns()[i])); - if (NodeType != EEVT::isUnknown) - AddMatcher(new CheckTypeMatcher((MVT::SimpleValueType)NodeType)); + if (DoTypeCheck) + AddMatcher(new CheckTypeMatcher(N->getType())); } /// EmitMatcherCode - Generate the code that matches the predicate of this @@ -567,7 +567,7 @@ assert(N->isLeaf() && "Must be a leaf"); if (IntInit *II = dynamic_cast(N->getLeafValue())) { - AddMatcher(new EmitIntegerMatcher(II->getValue(),N->getTypeNum(0))); + AddMatcher(new EmitIntegerMatcher(II->getValue(), N->getType())); ResultOps.push_back(NextRecordedOperandNo++); return; } @@ -575,14 +575,13 @@ // If this is an explicit register reference, handle it. if (DefInit *DI = dynamic_cast(N->getLeafValue())) { if (DI->getDef()->isSubClassOf("Register")) { - AddMatcher(new EmitRegisterMatcher(DI->getDef(), - N->getTypeNum(0))); + AddMatcher(new EmitRegisterMatcher(DI->getDef(), N->getType())); ResultOps.push_back(NextRecordedOperandNo++); return; } if (DI->getDef()->getName() == "zero_reg") { - AddMatcher(new EmitRegisterMatcher(0, N->getTypeNum(0))); + AddMatcher(new EmitRegisterMatcher(0, N->getType())); ResultOps.push_back(NextRecordedOperandNo++); return; } @@ -709,10 +708,10 @@ // Determine the result types. SmallVector ResultVTs; - if (NumResults != 0 && N->getTypeNum(0) != MVT::isVoid) { + if (NumResults != 0 && N->getType() != MVT::isVoid) { // FIXME2: If the node has multiple results, we should add them. For now, // preserve existing behavior?! - ResultVTs.push_back(N->getTypeNum(0)); + ResultVTs.push_back(N->getType()); } Modified: llvm/trunk/utils/TableGen/FastISelEmitter.cpp URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/utils/TableGen/FastISelEmitter.cpp?rev=98534&r1=98533&r2=98534&view=diff ============================================================================== --- llvm/trunk/utils/TableGen/FastISelEmitter.cpp (original) +++ llvm/trunk/utils/TableGen/FastISelEmitter.cpp Mon Mar 15 01:00:16 2010 @@ -73,10 +73,9 @@ if (!Op->getPredicateFns().empty()) return false; // For now, filter out any operand with multiple values. - if (Op->getExtTypes().size() != 1) - return false; + assert(Op->hasTypeSet() && "Type infererence not done?"); // For now, all the operands must have the same type. - if (Op->getTypeNum(0) != VT) + if (Op->getType() != VT) return false; if (!Op->isLeaf()) { if (Op->getOperator()->getName() == "imm") { @@ -296,10 +295,10 @@ Record *InstPatOp = InstPatNode->getOperator(); std::string OpcodeName = getOpcodeName(InstPatOp, CGP); - MVT::SimpleValueType RetVT = InstPatNode->getTypeNum(0); + MVT::SimpleValueType RetVT = InstPatNode->getType(); MVT::SimpleValueType VT = RetVT; if (InstPatNode->getNumChildren()) - VT = InstPatNode->getChild(0)->getTypeNum(0); + VT = InstPatNode->getChild(0)->getType(); // For now, filter out instructions which just set a register to // an Operand or an immediate, like MOV32ri. From sabre at nondot.org Mon Mar 15 01:03:22 2010 From: sabre at nondot.org (Chris Lattner) Date: Mon, 15 Mar 2010 06:03:22 -0000 Subject: [llvm-commits] [llvm] r98535 - /llvm/trunk/utils/TableGen/CodeGenDAGPatterns.cpp Message-ID: <20100315060322.731B42A6C12C@llvm.org> Author: lattner Date: Mon Mar 15 01:03:22 2010 New Revision: 98535 URL: http://llvm.org/viewvc/llvm-project?rev=98535&view=rev Log: eliminate some #if 0 code I added in r96905, type inference now enforces that input/output named values have hte same type. Modified: llvm/trunk/utils/TableGen/CodeGenDAGPatterns.cpp Modified: llvm/trunk/utils/TableGen/CodeGenDAGPatterns.cpp URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/utils/TableGen/CodeGenDAGPatterns.cpp?rev=98535&r1=98534&r2=98535&view=diff ============================================================================== --- llvm/trunk/utils/TableGen/CodeGenDAGPatterns.cpp (original) +++ llvm/trunk/utils/TableGen/CodeGenDAGPatterns.cpp Mon Mar 15 01:03:22 2010 @@ -2332,24 +2332,6 @@ if (SrcNames[I->first].first == 0) Pattern->error("Pattern has input without matching name in output: $" + I->first); - -#if 0 - const std::vector &SrcTypeVec = - SrcNames[I->first].first->getExtTypes(); - const std::vector &DstTypeVec = - I->second.first->getExtTypes(); - if (SrcTypeVec == DstTypeVec) continue; - - std::string SrcType, DstType; - for (unsigned i = 0, e = SrcTypeVec.size(); i != e; ++i) - SrcType += ":" + GetTypeName(SrcTypeVec[i]); - for (unsigned i = 0, e = DstTypeVec.size(); i != e; ++i) - DstType += ":" + GetTypeName(DstTypeVec[i]); - - Pattern->error("Variable $" + I->first + - " has different types in source (" + SrcType + - ") and dest (" + DstType + ") pattern!"); -#endif } // Scan all of the named values in the source pattern, rejecting them if the From sabre at nondot.org Mon Mar 15 01:15:35 2010 From: sabre at nondot.org (Chris Lattner) Date: Mon, 15 Mar 2010 06:15:35 -0000 Subject: [llvm-commits] [llvm] r98536 - in /llvm/trunk: include/llvm/MC/MCContext.h include/llvm/MC/MCSymbol.h lib/MC/MCContext.cpp Message-ID: <20100315061536.09FD52A6C12C@llvm.org> Author: lattner Date: Mon Mar 15 01:15:35 2010 New Revision: 98536 URL: http://llvm.org/viewvc/llvm-project?rev=98536&view=rev Log: fix a memory leak yjasskin pointed out: MCSymbol is bump pointer allocated and thus not freed. This is cool except that it contains and std::string so the string data didn't get freed. In any case there is no reason to redundantly store the string data in the MCSymbol anyway, just make the MCSymbol ref the string data in the MCContext StringMap. Modified: llvm/trunk/include/llvm/MC/MCContext.h llvm/trunk/include/llvm/MC/MCSymbol.h llvm/trunk/lib/MC/MCContext.cpp Modified: llvm/trunk/include/llvm/MC/MCContext.h URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/MC/MCContext.h?rev=98536&r1=98535&r2=98536&view=diff ============================================================================== --- llvm/trunk/include/llvm/MC/MCContext.h (original) +++ llvm/trunk/include/llvm/MC/MCContext.h Mon Mar 15 01:15:35 2010 @@ -65,8 +65,8 @@ /// reference and return it. /// /// @param Name - The symbol name, which must be unique across all symbols. - MCSymbol *GetOrCreateSymbol(StringRef Name); - MCSymbol *GetOrCreateSymbol(const Twine &Name); + MCSymbol *GetOrCreateSymbol(StringRef Name, bool isTemporary = false); + MCSymbol *GetOrCreateSymbol(const Twine &Name, bool isTemporary = false); /// GetOrCreateTemporarySymbol - Create a new assembler temporary symbol /// with the specified @p Name if it doesn't exist or return the existing Modified: llvm/trunk/include/llvm/MC/MCSymbol.h URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/MC/MCSymbol.h?rev=98536&r1=98535&r2=98536&view=diff ============================================================================== --- llvm/trunk/include/llvm/MC/MCSymbol.h (original) +++ llvm/trunk/include/llvm/MC/MCSymbol.h Mon Mar 15 01:15:35 2010 @@ -14,9 +14,7 @@ #ifndef LLVM_MC_MCSYMBOL_H #define LLVM_MC_MCSYMBOL_H -#include #include "llvm/ADT/StringRef.h" -#include "llvm/System/DataTypes.h" namespace llvm { class MCExpr; @@ -38,8 +36,9 @@ // FIXME: Use a PointerInt wrapper for this? static const MCSection *AbsolutePseudoSection; - /// Name - The name of the symbol. - std::string Name; + /// Name - The name of the symbol. The referred-to string data is actually + /// held by the StringMap that lives in MCContext. + StringRef Name; /// Section - The section the symbol is defined in. This is null for /// undefined symbols, and the special AbsolutePseudoSection value for @@ -56,14 +55,14 @@ private: // MCContext creates and uniques these. friend class MCContext; - MCSymbol(StringRef _Name, bool _IsTemporary) - : Name(_Name), Section(0), Value(0), IsTemporary(_IsTemporary) {} + MCSymbol(StringRef name, bool isTemporary) + : Name(name), Section(0), Value(0), IsTemporary(isTemporary) {} MCSymbol(const MCSymbol&); // DO NOT IMPLEMENT void operator=(const MCSymbol&); // DO NOT IMPLEMENT public: /// getName - Get the symbol name. - const std::string &getName() const { return Name; } + StringRef getName() const { return Name; } /// @name Symbol Type /// @{ Modified: llvm/trunk/lib/MC/MCContext.cpp URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/MC/MCContext.cpp?rev=98536&r1=98535&r2=98536&view=diff ============================================================================== --- llvm/trunk/lib/MC/MCContext.cpp (original) +++ llvm/trunk/lib/MC/MCContext.cpp Mon Mar 15 01:15:35 2010 @@ -23,18 +23,25 @@ // we don't need to free them here. } -MCSymbol *MCContext::GetOrCreateSymbol(StringRef Name) { +MCSymbol *MCContext::GetOrCreateSymbol(StringRef Name, bool isTemporary) { assert(!Name.empty() && "Normal symbols cannot be unnamed!"); - MCSymbol *&Entry = Symbols[Name]; - if (Entry) return Entry; - - return Entry = new (*this) MCSymbol(Name, false); + + // Do the lookup and get the entire StringMapEntry. We want access to the + // key if we are creating the entry. + StringMapEntry &Entry = Symbols.GetOrCreateValue(Name); + if (Entry.getValue()) return Entry.getValue(); + + // Ok, the entry doesn't already exist. Have the MCSymbol object itself refer + // to the copy of the string that is embedded in the StringMapEntry. + MCSymbol *Result = new (*this) MCSymbol(Entry.getKey(), isTemporary); + Entry.setValue(Result); + return Result; } -MCSymbol *MCContext::GetOrCreateSymbol(const Twine &Name) { +MCSymbol *MCContext::GetOrCreateSymbol(const Twine &Name, bool isTemporary) { SmallString<128> NameSV; Name.toVector(NameSV); - return GetOrCreateSymbol(NameSV.str()); + return GetOrCreateSymbol(NameSV.str(), isTemporary); } MCSymbol *MCContext::CreateTempSymbol() { @@ -50,10 +57,7 @@ return GetOrCreateTemporarySymbol(Twine(MAI.getPrivateGlobalPrefix()) + "tmp" + Twine(NextUniqueID++)); - // Otherwise create as usual. - MCSymbol *&Entry = Symbols[Name]; - if (Entry) return Entry; - return Entry = new (*this) MCSymbol(Name, true); + return GetOrCreateSymbol(Name, true); } MCSymbol *MCContext::GetOrCreateTemporarySymbol(const Twine &Name) { From sabre at nondot.org Mon Mar 15 01:23:53 2010 From: sabre at nondot.org (Chris Lattner) Date: Mon, 15 Mar 2010 06:23:53 -0000 Subject: [llvm-commits] [llvm] r98537 - in /llvm/trunk: include/llvm/MC/MCSection.h include/llvm/MC/MCSectionELF.h lib/CodeGen/TargetLoweringObjectFileImpl.cpp Message-ID: <20100315062353.278B82A6C12C@llvm.org> Author: lattner Date: Mon Mar 15 01:23:52 2010 New Revision: 98537 URL: http://llvm.org/viewvc/llvm-project?rev=98537&view=rev Log: fix MCSectionELF to not leak memory, just like I did for MCSymbol. MCSectionMachO is already fine (yay for fixed size arrays?), MCSectionCOFF still leaks. Modified: llvm/trunk/include/llvm/MC/MCSection.h llvm/trunk/include/llvm/MC/MCSectionELF.h llvm/trunk/lib/CodeGen/TargetLoweringObjectFileImpl.cpp Modified: llvm/trunk/include/llvm/MC/MCSection.h URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/MC/MCSection.h?rev=98537&r1=98536&r2=98537&view=diff ============================================================================== --- llvm/trunk/include/llvm/MC/MCSection.h (original) +++ llvm/trunk/include/llvm/MC/MCSection.h Mon Mar 15 01:23:52 2010 @@ -42,6 +42,8 @@ }; class MCSectionCOFF : public MCSection { + // FIXME: This memory is leaked because MCSectionCOFF is bump pointer + // allocated and this never gets freed. std::string Name; /// IsDirective - This is true if the section name is a directive, not Modified: llvm/trunk/include/llvm/MC/MCSectionELF.h URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/MC/MCSectionELF.h?rev=98537&r1=98536&r2=98537&view=diff ============================================================================== --- llvm/trunk/include/llvm/MC/MCSectionELF.h (original) +++ llvm/trunk/include/llvm/MC/MCSectionELF.h Mon Mar 15 01:23:52 2010 @@ -21,7 +21,9 @@ /// MCSectionELF - This represents a section on linux, lots of unix variants /// and some bare metal systems. class MCSectionELF : public MCSection { - std::string SectionName; + /// SectionName - This is the name of the section. The referenced memory is + /// owned by TargetLoweringObjectFileELF's ELFUniqueMap. + StringRef SectionName; /// Type - This is the sh_type field of a section, drawn from the enums below. unsigned Type; @@ -163,10 +165,7 @@ TARGET_INDEP_SHF = FIRST_TARGET_DEP_FLAG-1U }; - StringRef getSectionName() const { - return StringRef(SectionName); - } - + StringRef getSectionName() const { return SectionName; } unsigned getType() const { return Type; } unsigned getFlags() const { return Flags; } Modified: llvm/trunk/lib/CodeGen/TargetLoweringObjectFileImpl.cpp URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/CodeGen/TargetLoweringObjectFileImpl.cpp?rev=98537&r1=98536&r2=98537&view=diff ============================================================================== --- llvm/trunk/lib/CodeGen/TargetLoweringObjectFileImpl.cpp (original) +++ llvm/trunk/lib/CodeGen/TargetLoweringObjectFileImpl.cpp Mon Mar 15 01:23:52 2010 @@ -53,11 +53,13 @@ ELFUniqueMapTy &Map = *(ELFUniqueMapTy*)UniquingMap; // Do the lookup, if we have a hit, return it. - const MCSectionELF *&Entry = Map[Section]; - if (Entry) return Entry; + StringMapEntry &Entry = Map.GetOrCreateValue(Section); + if (Entry.getValue()) return Entry.getValue(); - return Entry = MCSectionELF::Create(Section, Type, Flags, Kind, IsExplicit, - getContext()); + MCSectionELF *Result = MCSectionELF::Create(Entry.getKey(), Type, Flags, Kind, + IsExplicit, getContext()); + Entry.setValue(Result); + return Result; } void TargetLoweringObjectFileELF::Initialize(MCContext &Ctx, From jyasskin at google.com Mon Mar 15 01:59:21 2010 From: jyasskin at google.com (Jeffrey Yasskin) Date: Mon, 15 Mar 2010 06:59:21 -0000 Subject: [llvm-commits] [llvm] r98538 - /llvm/trunk/include/llvm/MC/MCSectionELF.h Message-ID: <20100315065921.D79372A6C12C@llvm.org> Author: jyasskin Date: Mon Mar 15 01:59:21 2010 New Revision: 98538 URL: http://llvm.org/viewvc/llvm-project?rev=98538&view=rev Log: Don't save a temporary string into a StringRef field. Modified: llvm/trunk/include/llvm/MC/MCSectionELF.h Modified: llvm/trunk/include/llvm/MC/MCSectionELF.h URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/MC/MCSectionELF.h?rev=98538&r1=98537&r2=98538&view=diff ============================================================================== --- llvm/trunk/include/llvm/MC/MCSectionELF.h (original) +++ llvm/trunk/include/llvm/MC/MCSectionELF.h Mon Mar 15 01:59:21 2010 @@ -39,7 +39,7 @@ protected: MCSectionELF(StringRef Section, unsigned type, unsigned flags, SectionKind K, bool isExplicit) - : MCSection(K), SectionName(Section.str()), Type(type), Flags(flags), + : MCSection(K), SectionName(Section), Type(type), Flags(flags), IsExplicit(isExplicit) {} public: From baldrick at free.fr Mon Mar 15 03:43:45 2010 From: baldrick at free.fr (Duncan Sands) Date: Mon, 15 Mar 2010 09:43:45 +0100 Subject: [llvm-commits] [llvm] r98529 - in /llvm/trunk: autoconf/configure.ac cmake/config-ix.cmake cmake/modules/LLVMLibDeps.cmake configure include/llvm/Config/config.h.cmake include/llvm/Config/config.h.in include/llvm/System/Valgrind.h lib/System/CMakeLists.txt lib/System/Memory.cpp lib/System/Valgrind.cpp lib/Target/X86/X86JITInfo.cpp In-Reply-To: <20100315045755.5AC782A6C12C@llvm.org> References: <20100315045755.5AC782A6C12C@llvm.org> Message-ID: <4B9DF341.4040504@free.fr> > Tell Valgrind when we modify already-executed machine code so it knows > to re-instrument the code. We depend on the system valgrind.h to > avoid adding a new license. Nice! Ciao, Duncan. From baldrick at free.fr Mon Mar 15 09:01:45 2010 From: baldrick at free.fr (Duncan Sands) Date: Mon, 15 Mar 2010 14:01:45 -0000 Subject: [llvm-commits] [llvm] r98542 - /llvm/trunk/lib/Analysis/InlineCost.cpp Message-ID: <20100315140145.18D2C2A6C12C@llvm.org> Author: baldrick Date: Mon Mar 15 09:01:44 2010 New Revision: 98542 URL: http://llvm.org/viewvc/llvm-project?rev=98542&view=rev Log: Treat copysignl like the other copysign functions. Modified: llvm/trunk/lib/Analysis/InlineCost.cpp Modified: llvm/trunk/lib/Analysis/InlineCost.cpp URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Analysis/InlineCost.cpp?rev=98542&r1=98541&r2=98542&view=diff ============================================================================== --- llvm/trunk/lib/Analysis/InlineCost.cpp (original) +++ llvm/trunk/lib/Analysis/InlineCost.cpp Mon Mar 15 09:01:44 2010 @@ -120,7 +120,7 @@ StringRef Name = F->getName(); // These will all likely lower to a single selection DAG node. - if (Name == "copysign" || Name == "copysignf" || + if (Name == "copysign" || Name == "copysignf" || Name == "copysignl" || Name == "fabs" || Name == "fabsf" || Name == "fabsl" || Name == "sin" || Name == "sinf" || Name == "sinl" || Name == "cos" || Name == "cosf" || Name == "cosl" || From clattner at apple.com Mon Mar 15 10:46:11 2010 From: clattner at apple.com (Chris Lattner) Date: Mon, 15 Mar 2010 08:46:11 -0700 Subject: [llvm-commits] [llvm] r98538 - /llvm/trunk/include/llvm/MC/MCSectionELF.h In-Reply-To: <20100315065921.D79372A6C12C@llvm.org> References: <20100315065921.D79372A6C12C@llvm.org> Message-ID: <80C1F24D-7514-4B46-ABCE-83E5EC86ADCA@apple.com> On Mar 14, 2010, at 11:59 PM, Jeffrey Yasskin wrote: > Author: jyasskin > Date: Mon Mar 15 01:59:21 2010 > New Revision: 98538 > > URL: http://llvm.org/viewvc/llvm-project?rev=98538&view=rev > Log: > Don't save a temporary string into a StringRef field. Doh, thanks!! From sabre at nondot.org Mon Mar 15 11:05:15 2010 From: sabre at nondot.org (Chris Lattner) Date: Mon, 15 Mar 2010 16:05:15 -0000 Subject: [llvm-commits] [llvm] r98547 - /llvm/trunk/lib/CodeGen/SelectionDAG/SelectionDAG.cpp Message-ID: <20100315160515.9D3012A6C12C@llvm.org> Author: lattner Date: Mon Mar 15 11:05:15 2010 New Revision: 98547 URL: http://llvm.org/viewvc/llvm-project?rev=98547&view=rev Log: sink the call to VT.getSizeInBits() down into its uses, not all unary nodes necessarily have a simple result type. Modified: llvm/trunk/lib/CodeGen/SelectionDAG/SelectionDAG.cpp Modified: llvm/trunk/lib/CodeGen/SelectionDAG/SelectionDAG.cpp URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/CodeGen/SelectionDAG/SelectionDAG.cpp?rev=98547&r1=98546&r2=98547&view=diff ============================================================================== --- llvm/trunk/lib/CodeGen/SelectionDAG/SelectionDAG.cpp (original) +++ llvm/trunk/lib/CodeGen/SelectionDAG/SelectionDAG.cpp Mon Mar 15 11:05:15 2010 @@ -2329,22 +2329,20 @@ // Constant fold unary operations with an integer constant operand. if (ConstantSDNode *C = dyn_cast(Operand.getNode())) { const APInt &Val = C->getAPIntValue(); - unsigned BitWidth = VT.getSizeInBits(); switch (Opcode) { default: break; case ISD::SIGN_EXTEND: - return getConstant(APInt(Val).sextOrTrunc(BitWidth), VT); + return getConstant(APInt(Val).sext(VT.getSizeInBits()), VT); case ISD::ANY_EXTEND: case ISD::ZERO_EXTEND: case ISD::TRUNCATE: - return getConstant(APInt(Val).zextOrTrunc(BitWidth), VT); + return getConstant(APInt(Val).zextOrTrunc(VT.getSizeInBits()), VT); case ISD::UINT_TO_FP: case ISD::SINT_TO_FP: { const uint64_t zero[] = {0, 0}; - // No compile time operations on this type. - if (VT==MVT::ppcf128) - break; - APFloat apf = APFloat(APInt(BitWidth, 2, zero)); + // No compile time operations on ppcf128. + if (VT == MVT::ppcf128) break; + APFloat apf = APFloat(APInt(VT.getSizeInBits(), 2, zero)); (void)apf.convertFromAPInt(Val, Opcode==ISD::SINT_TO_FP, APFloat::rmNearestTiesToEven); From sabre at nondot.org Mon Mar 15 11:15:56 2010 From: sabre at nondot.org (Chris Lattner) Date: Mon, 15 Mar 2010 16:15:56 -0000 Subject: [llvm-commits] [llvm] r98548 - /llvm/trunk/lib/CodeGen/SelectionDAG/SelectionDAG.cpp Message-ID: <20100315161556.DB6802A6C12C@llvm.org> Author: lattner Date: Mon Mar 15 11:15:56 2010 New Revision: 98548 URL: http://llvm.org/viewvc/llvm-project?rev=98548&view=rev Log: SIGN_EXTEND from the same type as the dest is valid. Modified: llvm/trunk/lib/CodeGen/SelectionDAG/SelectionDAG.cpp Modified: llvm/trunk/lib/CodeGen/SelectionDAG/SelectionDAG.cpp URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/CodeGen/SelectionDAG/SelectionDAG.cpp?rev=98548&r1=98547&r2=98548&view=diff ============================================================================== --- llvm/trunk/lib/CodeGen/SelectionDAG/SelectionDAG.cpp (original) +++ llvm/trunk/lib/CodeGen/SelectionDAG/SelectionDAG.cpp Mon Mar 15 11:15:56 2010 @@ -2332,7 +2332,7 @@ switch (Opcode) { default: break; case ISD::SIGN_EXTEND: - return getConstant(APInt(Val).sext(VT.getSizeInBits()), VT); + return getConstant(APInt(Val).sextOrTrunc(VT.getSizeInBits()), VT); case ISD::ANY_EXTEND: case ISD::ZERO_EXTEND: case ISD::TRUNCATE: From sabre at nondot.org Mon Mar 15 11:37:43 2010 From: sabre at nondot.org (Chris Lattner) Date: Mon, 15 Mar 2010 16:37:43 -0000 Subject: [llvm-commits] [llvm] r98550 - /llvm/trunk/lib/CodeGen/UnreachableBlockElim.cpp Message-ID: <20100315163743.158272A6C12C@llvm.org> Author: lattner Date: Mon Mar 15 11:37:42 2010 New Revision: 98550 URL: http://llvm.org/viewvc/llvm-project?rev=98550&view=rev Log: don't eliminate address-taken blocks here. Modified: llvm/trunk/lib/CodeGen/UnreachableBlockElim.cpp Modified: llvm/trunk/lib/CodeGen/UnreachableBlockElim.cpp URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/CodeGen/UnreachableBlockElim.cpp?rev=98550&r1=98549&r2=98550&view=diff ============================================================================== --- llvm/trunk/lib/CodeGen/UnreachableBlockElim.cpp (original) +++ llvm/trunk/lib/CodeGen/UnreachableBlockElim.cpp Mon Mar 15 11:37:42 2010 @@ -58,13 +58,25 @@ return new UnreachableBlockElim(); } +static void MarkReachableFrom(BasicBlock *BB, + SmallPtrSet &Reachable) { + for (df_ext_iterator > I = + df_ext_begin(BB, Reachable), E = df_ext_end(BB, Reachable); I != E; ++I) + ; // Mark all reachable blocks. +} + bool UnreachableBlockElim::runOnFunction(Function &F) { SmallPtrSet Reachable; // Mark all reachable blocks. - for (df_ext_iterator > I = - df_ext_begin(&F, Reachable), E = df_ext_end(&F, Reachable); I != E; ++I) - /* Mark all reachable blocks */; + MarkReachableFrom(&F.getEntryBlock(), Reachable); + + // Mark any address-taken blocks. We don't want codegen to delete these + // because the address may already be referenced by another function and the + // label may be referenced. + for (Function::iterator I = F.begin(), E = F.end(); I != E; ++I) + if (I->hasAddressTaken() && !Reachable.count(I)) + MarkReachableFrom(I, Reachable); // Loop over all dead blocks, remembering them and deleting all instructions // in them. From aaronngray.lists at googlemail.com Mon Mar 15 12:06:26 2010 From: aaronngray.lists at googlemail.com (Aaron Gray) Date: Mon, 15 Mar 2010 17:06:26 +0000 Subject: [llvm-commits] Extract MachObjectWriter class to own header and code files Message-ID: <9719867c1003151006r720d53cewebc80de9802ed238@mail.gmail.com> Hi, This patch extracts 'class MachObjectWriter' into its own .h and .cpp files. Tested on MSVC and Cygwin. Aaron -------------- next part -------------- An HTML attachment was scrubbed... URL: http://lists.cs.uiuc.edu/pipermail/llvm-commits/attachments/20100315/b76ca7e7/attachment.html -------------- next part -------------- A non-text attachment was scrubbed... Name: MachObjectWriter.patch Type: application/octet-stream Size: 79946 bytes Desc: not available Url : http://lists.cs.uiuc.edu/pipermail/llvm-commits/attachments/20100315/b76ca7e7/attachment.obj From gohman at apple.com Mon Mar 15 13:34:08 2010 From: gohman at apple.com (Dan Gohman) Date: Mon, 15 Mar 2010 11:34:08 -0700 Subject: [llvm-commits] [llvm] r98550 - /llvm/trunk/lib/CodeGen/UnreachableBlockElim.cpp In-Reply-To: <20100315163743.158272A6C12C@llvm.org> References: <20100315163743.158272A6C12C@llvm.org> Message-ID: <720F6EC5-EC9C-4962-8B65-919977E063DE@apple.com> On Mar 15, 2010, at 9:37 AM, Chris Lattner wrote: > Author: lattner > Date: Mon Mar 15 11:37:42 2010 > New Revision: 98550 > > URL: http://llvm.org/viewvc/llvm-project?rev=98550&view=rev > Log: > don't eliminate address-taken blocks here. IIRC, the main reason for UnreachableBlockElim is that CodeGen's liveness analysis requires all blocks be reachable. If address-taken blocks have no CFG predecessors and aren't deleted, wouldn't it re-introduce the problems UnreachableBlockElim was intended to solve? Dan From dpatel at apple.com Mon Mar 15 13:33:47 2010 From: dpatel at apple.com (Devang Patel) Date: Mon, 15 Mar 2010 18:33:47 -0000 Subject: [llvm-commits] [llvm] r98556 - in /llvm/trunk/lib/CodeGen: AsmPrinter/AsmPrinter.cpp AsmPrinter/DwarfDebug.cpp AsmPrinter/DwarfDebug.h SelectionDAG/SelectionDAGISel.cpp Message-ID: <20100315183347.2CA4E2A6C12C@llvm.org> Author: dpatel Date: Mon Mar 15 13:33:46 2010 New Revision: 98556 URL: http://llvm.org/viewvc/llvm-project?rev=98556&view=rev Log: Emit dwarf variable info communicated by code generator through DBG_VALUE machine instructions. This is a work in progress. Modified: llvm/trunk/lib/CodeGen/AsmPrinter/AsmPrinter.cpp llvm/trunk/lib/CodeGen/AsmPrinter/DwarfDebug.cpp llvm/trunk/lib/CodeGen/AsmPrinter/DwarfDebug.h llvm/trunk/lib/CodeGen/SelectionDAG/SelectionDAGISel.cpp Modified: llvm/trunk/lib/CodeGen/AsmPrinter/AsmPrinter.cpp URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/CodeGen/AsmPrinter/AsmPrinter.cpp?rev=98556&r1=98555&r2=98556&view=diff ============================================================================== --- llvm/trunk/lib/CodeGen/AsmPrinter/AsmPrinter.cpp (original) +++ llvm/trunk/lib/CodeGen/AsmPrinter/AsmPrinter.cpp Mon Mar 15 13:33:46 2010 @@ -1309,6 +1309,8 @@ if (!MAI || !DW || !MAI->doesSupportDebugInformation() || !DW->ShouldEmitDwarfDebug()) return; + if (MI->getOpcode() == TargetOpcode::DBG_VALUE) + return; DebugLoc DL = MI->getDebugLoc(); if (DL.isUnknown()) return; Modified: llvm/trunk/lib/CodeGen/AsmPrinter/DwarfDebug.cpp URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/CodeGen/AsmPrinter/DwarfDebug.cpp?rev=98556&r1=98555&r2=98556&view=diff ============================================================================== --- llvm/trunk/lib/CodeGen/AsmPrinter/DwarfDebug.cpp (original) +++ llvm/trunk/lib/CodeGen/AsmPrinter/DwarfDebug.cpp Mon Mar 15 13:33:46 2010 @@ -148,16 +148,21 @@ class DbgVariable { DIVariable Var; // Variable Descriptor. unsigned FrameIndex; // Variable frame index. + const MachineInstr *DbgValueMInsn; // DBG_VALUE DbgVariable *const AbstractVar; // Abstract variable for this variable. DIE *TheDIE; public: // AbsVar may be NULL. DbgVariable(DIVariable V, unsigned I, DbgVariable *AbsVar) - : Var(V), FrameIndex(I), AbstractVar(AbsVar), TheDIE(0) {} + : Var(V), FrameIndex(I), DbgValueMInsn(0), AbstractVar(AbsVar), TheDIE(0) {} + DbgVariable(DIVariable V, const MachineInstr *MI, DbgVariable *AbsVar) + : Var(V), FrameIndex(0), DbgValueMInsn(MI), AbstractVar(AbsVar), TheDIE(0) + {} // Accessors. DIVariable getVariable() const { return Var; } unsigned getFrameIndex() const { return FrameIndex; } + const MachineInstr *getDbgValue() const { return DbgValueMInsn; } DbgVariable *getAbstractVariable() const { return AbstractVar; } void setDIE(DIE *D) { TheDIE = D; } DIE *getDIE() const { return TheDIE; } @@ -1493,17 +1498,41 @@ // Add variable address. if (!Scope->isAbstractScope()) { - MachineLocation Location; - unsigned FrameReg; - int Offset = RI->getFrameIndexReference(*MF, DV->getFrameIndex(), FrameReg); - Location.set(FrameReg, Offset); - - if (VD.hasComplexAddress()) - addComplexAddress(DV, VariableDie, dwarf::DW_AT_location, Location); - else if (VD.isBlockByrefVariable()) - addBlockByrefAddress(DV, VariableDie, dwarf::DW_AT_location, Location); - else - addAddress(VariableDie, dwarf::DW_AT_location, Location); + // Check if variable is described by DBG_VALUE instruction. + if (const MachineInstr *DbgValueInsn = DV->getDbgValue()) { + if (DbgValueInsn->getNumOperands() == 3) { + // FIXME : Handle getNumOperands != 3 + if (DbgValueInsn->getOperand(0).getType() + == MachineOperand::MO_Register + && DbgValueInsn->getOperand(0).getReg()) { + MachineLocation Location; + Location.set(DbgValueInsn->getOperand(0).getReg()); + addAddress(VariableDie, dwarf::DW_AT_location, Location); + } else if (DbgValueInsn->getOperand(0).getType() == + MachineOperand::MO_Immediate) { + DIEBlock *Block = new DIEBlock(); + unsigned Imm = DbgValueInsn->getOperand(0).getImm(); + addUInt(Block, 0, dwarf::DW_FORM_udata, Imm); + addBlock(VariableDie, dwarf::DW_AT_const_value, 0, Block); + } else { + //FIXME : Handle other operand types. + delete VariableDie; + return NULL; + } + } + } else { + MachineLocation Location; + unsigned FrameReg; + int Offset = RI->getFrameIndexReference(*MF, DV->getFrameIndex(), FrameReg); + Location.set(FrameReg, Offset); + + if (VD.hasComplexAddress()) + addComplexAddress(DV, VariableDie, dwarf::DW_AT_location, Location); + else if (VD.isBlockByrefVariable()) + addBlockByrefAddress(DV, VariableDie, dwarf::DW_AT_location, Location); + else + addAddress(VariableDie, dwarf::DW_AT_location, Location); + } } if (Tag == dwarf::DW_TAG_formal_parameter && VD.getType().isArtificial()) @@ -1928,6 +1957,27 @@ return AbsDbgVariable; } +/// findAbstractVariable - Find abstract variable, if any, associated with Var. +/// FIXME : Refactor findAbstractVariable. +DbgVariable *DwarfDebug::findAbstractVariable(DIVariable &Var, + const MachineInstr *MI, + DILocation &ScopeLoc) { + + DbgVariable *AbsDbgVariable = AbstractVariables.lookup(Var.getNode()); + if (AbsDbgVariable) + return AbsDbgVariable; + + DbgScope *Scope = AbstractScopes.lookup(ScopeLoc.getScope().getNode()); + if (!Scope) + return NULL; + + AbsDbgVariable = new DbgVariable(Var, MI, + NULL /* No more-abstract variable*/); + Scope->addVariable(AbsDbgVariable); + AbstractVariables[Var.getNode()] = AbsDbgVariable; + return AbsDbgVariable; +} + /// collectVariableInfo - Populate DbgScope entries with variables' info. void DwarfDebug::collectVariableInfo() { if (!MMI) return; @@ -1953,6 +2003,43 @@ DbgVariable *RegVar = new DbgVariable(DV, VP.first, AbsDbgVariable); Scope->addVariable(RegVar); } + + // Collect variable information from DBG_VALUE machine instructions; + for (MachineFunction::const_iterator I = MF->begin(), E = MF->end(); + I != E; ++I) { + for (MachineBasicBlock::const_iterator II = I->begin(), IE = I->end(); + II != IE; ++II) { + const MachineInstr *MInsn = II; + if (MInsn->getOpcode() != TargetOpcode::DBG_VALUE) + continue; + // FIXME : Lift this restriction. + if (MInsn->getNumOperands() != 3) + continue; + DIVariable DV((MDNode*)(MInsn->getOperand(MInsn->getNumOperands() - 1).getMetadata())); + if (DV.getTag() == dwarf::DW_TAG_arg_variable) { + // FIXME Handle inlined subroutine arguments. + DbgVariable *ArgVar = new DbgVariable(DV, MInsn, NULL); + CurrentFnDbgScope->addVariable(ArgVar); + continue; + } + + DebugLoc DL = MInsn->getDebugLoc(); + if (DL.isUnknown()) continue; + DILocation ScopeLoc = MF->getDILocation(DL); + DbgScope *Scope = + ConcreteScopes.lookup(ScopeLoc.getOrigLocation().getNode()); + if (!Scope) + Scope = DbgScopeMap.lookup(ScopeLoc.getScope().getNode()); + // If variable scope is not found then skip this variable. + if (!Scope) + continue; + + DbgVariable *AbsDbgVariable = findAbstractVariable(DV, MInsn, + ScopeLoc); + DbgVariable *RegVar = new DbgVariable(DV, MInsn, AbsDbgVariable); + Scope->addVariable(RegVar); + } + } } /// beginScope - Process beginning of a scope starting at Label. @@ -2022,6 +2109,8 @@ for (MachineBasicBlock::const_iterator II = I->begin(), IE = I->end(); II != IE; ++II) { const MachineInstr *MInsn = II; + // FIXME : Remove DBG_VALUE check. + if (MInsn->getOpcode() == TargetOpcode::DBG_VALUE) continue; MIIndexMap[MInsn] = MIIndex++; DebugLoc DL = MInsn->getDebugLoc(); if (DL.isUnknown()) continue; @@ -2042,6 +2131,8 @@ for (MachineBasicBlock::const_iterator II = I->begin(), IE = I->end(); II != IE; ++II) { const MachineInstr *MInsn = II; + // FIXME : Remove DBG_VALUE check. + if (MInsn->getOpcode() == TargetOpcode::DBG_VALUE) continue; DebugLoc DL = MInsn->getDebugLoc(); if (DL.isUnknown()) continue; DILocation DLT = MF->getDILocation(DL); Modified: llvm/trunk/lib/CodeGen/AsmPrinter/DwarfDebug.h URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/CodeGen/AsmPrinter/DwarfDebug.h?rev=98556&r1=98555&r2=98556&view=diff ============================================================================== --- llvm/trunk/lib/CodeGen/AsmPrinter/DwarfDebug.h (original) +++ llvm/trunk/lib/CodeGen/AsmPrinter/DwarfDebug.h Mon Mar 15 13:33:46 2010 @@ -361,6 +361,8 @@ /// findAbstractVariable - Find abstract variable associated with Var. DbgVariable *findAbstractVariable(DIVariable &Var, unsigned FrameIdx, DILocation &Loc); + DbgVariable *findAbstractVariable(DIVariable &Var, const MachineInstr *MI, + DILocation &Loc); /// updateSubprogramScopeDIE - Find DIE for the given subprogram and /// attach appropriate DW_AT_low_pc and DW_AT_high_pc attributes. Modified: llvm/trunk/lib/CodeGen/SelectionDAG/SelectionDAGISel.cpp URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/CodeGen/SelectionDAG/SelectionDAGISel.cpp?rev=98556&r1=98555&r2=98556&view=diff ============================================================================== --- llvm/trunk/lib/CodeGen/SelectionDAG/SelectionDAGISel.cpp (original) +++ llvm/trunk/lib/CodeGen/SelectionDAG/SelectionDAGISel.cpp Mon Mar 15 13:33:46 2010 @@ -368,8 +368,6 @@ static void SetDebugLoc(unsigned MDDbgKind, Instruction *I, SelectionDAGBuilder *SDB, FastISel *FastIS, MachineFunction *MF) { - if (isa(I)) return; - if (MDNode *Dbg = I->getMetadata(MDDbgKind)) { DILocation DILoc(Dbg); DebugLoc Loc = ExtractDebugLocation(DILoc, MF->getDebugLocInfo()); From gohman at apple.com Mon Mar 15 13:34:46 2010 From: gohman at apple.com (Dan Gohman) Date: Mon, 15 Mar 2010 11:34:46 -0700 Subject: [llvm-commits] [llvm] r98548 - /llvm/trunk/lib/CodeGen/SelectionDAG/SelectionDAG.cpp In-Reply-To: <20100315161556.DB6802A6C12C@llvm.org> References: <20100315161556.DB6802A6C12C@llvm.org> Message-ID: <8AB4A794-064E-4DEC-AF09-DF9514785060@apple.com> On Mar 15, 2010, at 9:15 AM, Chris Lattner wrote: > Author: lattner > Date: Mon Mar 15 11:15:56 2010 > New Revision: 98548 > > URL: http://llvm.org/viewvc/llvm-project?rev=98548&view=rev > Log: > SIGN_EXTEND from the same type as the dest is valid. It is? This is inconsistent with LLVM IR. What code is creating identity SIGN_EXTENDs, and why is it inconvenient for it to use BIT_CONVERT instead? Dan From clattner at apple.com Mon Mar 15 13:41:15 2010 From: clattner at apple.com (Chris Lattner) Date: Mon, 15 Mar 2010 11:41:15 -0700 Subject: [llvm-commits] [llvm] r98548 - /llvm/trunk/lib/CodeGen/SelectionDAG/SelectionDAG.cpp In-Reply-To: <8AB4A794-064E-4DEC-AF09-DF9514785060@apple.com> References: <20100315161556.DB6802A6C12C@llvm.org> <8AB4A794-064E-4DEC-AF09-DF9514785060@apple.com> Message-ID: <67EA0393-9ABB-4D28-AD75-8DABAC8CCEEE@apple.com> On Mar 15, 2010, at 11:34 AM, Dan Gohman wrote: > > On Mar 15, 2010, at 9:15 AM, Chris Lattner wrote: > >> Author: lattner >> Date: Mon Mar 15 11:15:56 2010 >> New Revision: 98548 >> >> URL: http://llvm.org/viewvc/llvm-project?rev=98548&view=rev >> Log: >> SIGN_EXTEND from the same type as the dest is valid. > > It is? This is inconsistent with LLVM IR. What code is creating > identity SIGN_EXTENDs, and why is it inconvenient for it to use > BIT_CONVERT instead? getNode(ISD::SIGN_EXTEND) is currently allowed to be called with src/dst of the same type, it transparently returns the input. No SIGN_EXTEND nodes are ever created with source = dest. -Chris From sabre at nondot.org Mon Mar 15 13:42:01 2010 From: sabre at nondot.org (Chris Lattner) Date: Mon, 15 Mar 2010 18:42:01 -0000 Subject: [llvm-commits] [llvm] r98558 - /llvm/trunk/lib/CodeGen/UnreachableBlockElim.cpp Message-ID: <20100315184201.898792A6C12C@llvm.org> Author: lattner Date: Mon Mar 15 13:42:01 2010 New Revision: 98558 URL: http://llvm.org/viewvc/llvm-project?rev=98558&view=rev Log: revert r98550, it isn't necessary or sufficient. Modified: llvm/trunk/lib/CodeGen/UnreachableBlockElim.cpp Modified: llvm/trunk/lib/CodeGen/UnreachableBlockElim.cpp URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/CodeGen/UnreachableBlockElim.cpp?rev=98558&r1=98557&r2=98558&view=diff ============================================================================== --- llvm/trunk/lib/CodeGen/UnreachableBlockElim.cpp (original) +++ llvm/trunk/lib/CodeGen/UnreachableBlockElim.cpp Mon Mar 15 13:42:01 2010 @@ -58,25 +58,13 @@ return new UnreachableBlockElim(); } -static void MarkReachableFrom(BasicBlock *BB, - SmallPtrSet &Reachable) { - for (df_ext_iterator > I = - df_ext_begin(BB, Reachable), E = df_ext_end(BB, Reachable); I != E; ++I) - ; // Mark all reachable blocks. -} - bool UnreachableBlockElim::runOnFunction(Function &F) { SmallPtrSet Reachable; // Mark all reachable blocks. - MarkReachableFrom(&F.getEntryBlock(), Reachable); - - // Mark any address-taken blocks. We don't want codegen to delete these - // because the address may already be referenced by another function and the - // label may be referenced. - for (Function::iterator I = F.begin(), E = F.end(); I != E; ++I) - if (I->hasAddressTaken() && !Reachable.count(I)) - MarkReachableFrom(I, Reachable); + for (df_ext_iterator > I = + df_ext_begin(&F, Reachable), E = df_ext_end(&F, Reachable); I != E; ++I) + /* Mark all reachable blocks */; // Loop over all dead blocks, remembering them and deleting all instructions // in them. From clattner at apple.com Mon Mar 15 13:42:44 2010 From: clattner at apple.com (Chris Lattner) Date: Mon, 15 Mar 2010 11:42:44 -0700 Subject: [llvm-commits] [llvm] r98550 - /llvm/trunk/lib/CodeGen/UnreachableBlockElim.cpp In-Reply-To: <720F6EC5-EC9C-4962-8B65-919977E063DE@apple.com> References: <20100315163743.158272A6C12C@llvm.org> <720F6EC5-EC9C-4962-8B65-919977E063DE@apple.com> Message-ID: <178C1462-25F7-4958-BCCF-2CA83EF044C4@apple.com> On Mar 15, 2010, at 11:34 AM, Dan Gohman wrote: > > On Mar 15, 2010, at 9:37 AM, Chris Lattner wrote: > >> Author: lattner >> Date: Mon Mar 15 11:37:42 2010 >> New Revision: 98550 >> >> URL: http://llvm.org/viewvc/llvm-project?rev=98550&view=rev >> Log: >> don't eliminate address-taken blocks here. > > IIRC, the main reason for UnreachableBlockElim is that CodeGen's liveness analysis > requires all blocks be reachable. If address-taken blocks have no CFG predecessors > and aren't deleted, wouldn't it re-introduce the problems UnreachableBlockElim was > intended to solve? CGP generally deletes blocks as well, but you're right and this patch isn't required anyway. I reverted it. From evan.cheng at apple.com Mon Mar 15 13:54:49 2010 From: evan.cheng at apple.com (Evan Cheng) Date: Mon, 15 Mar 2010 18:54:49 -0000 Subject: [llvm-commits] [llvm] r98561 - in /llvm/trunk/lib/Target/X86: X86ISelLowering.cpp X86ISelLowering.h Message-ID: <20100315185449.3B4872A6C12C@llvm.org> Author: evancheng Date: Mon Mar 15 13:54:48 2010 New Revision: 98561 URL: http://llvm.org/viewvc/llvm-project?rev=98561&view=rev Log: Avoid sibcall optimization if either caller or callee is using sret semantics. Modified: llvm/trunk/lib/Target/X86/X86ISelLowering.cpp llvm/trunk/lib/Target/X86/X86ISelLowering.h Modified: llvm/trunk/lib/Target/X86/X86ISelLowering.cpp URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Target/X86/X86ISelLowering.cpp?rev=98561&r1=98560&r2=98561&view=diff ============================================================================== --- llvm/trunk/lib/Target/X86/X86ISelLowering.cpp (original) +++ llvm/trunk/lib/Target/X86/X86ISelLowering.cpp Mon Mar 15 13:54:48 2010 @@ -1524,7 +1524,6 @@ DebugLoc dl, SelectionDAG &DAG, SmallVectorImpl &InVals) { - MachineFunction &MF = DAG.getMachineFunction(); X86MachineFunctionInfo *FuncInfo = MF.getInfo(); @@ -1826,7 +1825,8 @@ if (isTailCall) { // Check if it's really possible to do a tail call. - isTailCall = IsEligibleForTailCallOptimization(Callee, CallConv, isVarArg, + isTailCall = IsEligibleForTailCallOptimization(Callee, CallConv, + isVarArg, IsStructRet, MF.getFunction()->hasStructRetAttr(), Outs, Ins, DAG); // Sibcalls are automatically detected tailcalls which do not require @@ -2324,6 +2324,8 @@ X86TargetLowering::IsEligibleForTailCallOptimization(SDValue Callee, CallingConv::ID CalleeCC, bool isVarArg, + bool isCalleeStructRet, + bool isCallerStructRet, const SmallVectorImpl &Outs, const SmallVectorImpl &Ins, SelectionDAG& DAG) const { @@ -2343,10 +2345,15 @@ // Look for obvious safe cases to perform tail call optimization that does not // requite ABI changes. This is what gcc calls sibcall. - // Do not tail call optimize vararg calls for now. + // Do not sibcall optimize vararg calls for now. if (isVarArg) return false; + // Also avoid sibcall optimization if either caller or callee uses struct + // return semantics. + if (isCalleeStructRet || isCallerStructRet) + return false; + // If the callee takes no arguments then go on to check the results of the // call. if (!Outs.empty()) { Modified: llvm/trunk/lib/Target/X86/X86ISelLowering.h URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Target/X86/X86ISelLowering.h?rev=98561&r1=98560&r2=98561&view=diff ============================================================================== --- llvm/trunk/lib/Target/X86/X86ISelLowering.h (original) +++ llvm/trunk/lib/Target/X86/X86ISelLowering.h Mon Mar 15 13:54:48 2010 @@ -630,6 +630,8 @@ bool IsEligibleForTailCallOptimization(SDValue Callee, CallingConv::ID CalleeCC, bool isVarArg, + bool isCalleeStructRet, + bool isCallerStructRet, const SmallVectorImpl &Outs, const SmallVectorImpl &Ins, SelectionDAG& DAG) const; From isanbard at gmail.com Mon Mar 15 14:01:37 2010 From: isanbard at gmail.com (Bill Wendling) Date: Mon, 15 Mar 2010 19:01:37 -0000 Subject: [llvm-commits] [test-suite] r98562 - /test-suite/trunk/Makefile.programs Message-ID: <20100315190137.78DD72A6C12C@llvm.org> Author: void Date: Mon Mar 15 14:01:37 2010 New Revision: 98562 URL: http://llvm.org/viewvc/llvm-project?rev=98562&view=rev Log: Experiment over. Modified: test-suite/trunk/Makefile.programs Modified: test-suite/trunk/Makefile.programs URL: http://llvm.org/viewvc/llvm-project/test-suite/trunk/Makefile.programs?rev=98562&r1=98561&r2=98562&view=diff ============================================================================== --- test-suite/trunk/Makefile.programs (original) +++ test-suite/trunk/Makefile.programs Mon Mar 15 14:01:37 2010 @@ -232,10 +232,10 @@ LLCBETAOPTION := -sched=simple endif ifeq ($(ARCH),x86_64) -LLCBETAOPTION := -enable-x86-eh-test +LLCBETAOPTION := endif ifeq ($(ARCH),x86) -LLCBETAOPTION := -enable-x86-eh-test +LLCBETAOPTION := endif ifeq ($(ARCH),Sparc) LLCBETAOPTION := -enable-sparc-v9-insts From isanbard at gmail.com Mon Mar 15 14:04:37 2010 From: isanbard at gmail.com (Bill Wendling) Date: Mon, 15 Mar 2010 19:04:37 -0000 Subject: [llvm-commits] [llvm] r98564 - in /llvm/trunk/lib/Target/X86: X86ISelLowering.cpp X86TargetObjectFile.cpp X86TargetObjectFile.h Message-ID: <20100315190439.D26CC2A6C12C@llvm.org> Author: void Date: Mon Mar 15 14:04:37 2010 New Revision: 98564 URL: http://llvm.org/viewvc/llvm-project?rev=98564&view=rev Log: Place the LSDA into the TEXT section for x86 Darwin. If the global it's pointing to is local to the translation unit, we need to place fill the value of that symbol into the non-lazy pointer. This should conclude all Darwin changes for placing the LSDA into the TEXT section. There is some cleanup to do. I.e., there's no longer a special need for target-specific code here. But that can come later. Modified: llvm/trunk/lib/Target/X86/X86ISelLowering.cpp llvm/trunk/lib/Target/X86/X86TargetObjectFile.cpp llvm/trunk/lib/Target/X86/X86TargetObjectFile.h Modified: llvm/trunk/lib/Target/X86/X86ISelLowering.cpp URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Target/X86/X86ISelLowering.cpp?rev=98564&r1=98563&r2=98564&view=diff ============================================================================== --- llvm/trunk/lib/Target/X86/X86ISelLowering.cpp (original) +++ llvm/trunk/lib/Target/X86/X86ISelLowering.cpp Mon Mar 15 14:04:37 2010 @@ -70,53 +70,14 @@ static SDValue getMOVL(SelectionDAG &DAG, DebugLoc dl, EVT VT, SDValue V1, SDValue V2); -// FIXME: This is for a test. -static cl::opt -EnableX86EHTest("enable-x86-eh-test", cl::Hidden); - -namespace llvm { - class X86_test_MachoTargetObjectFile : public TargetLoweringObjectFileMachO { - public: - virtual void Initialize(MCContext &Ctx, const TargetMachine &TM) { - TargetLoweringObjectFileMachO::Initialize(Ctx, TM); - - // Exception Handling. - LSDASection = getMachOSection("__TEXT", "__gcc_except_tab", 0, - SectionKind::getReadOnlyWithRel()); - } - - virtual unsigned getTTypeEncoding() const { - return DW_EH_PE_indirect | DW_EH_PE_pcrel | DW_EH_PE_sdata4; - } - }; - - class X8664_test_MachoTargetObjectFile : public X8664_MachoTargetObjectFile { - public: - virtual void Initialize(MCContext &Ctx, const TargetMachine &TM) { - TargetLoweringObjectFileMachO::Initialize(Ctx, TM); - - // Exception Handling. - LSDASection = getMachOSection("__TEXT", "__gcc_except_tab", 0, - SectionKind::getReadOnlyWithRel()); - } - - virtual unsigned getTTypeEncoding() const { - return DW_EH_PE_indirect | DW_EH_PE_pcrel | DW_EH_PE_sdata4; - } - }; -} - static TargetLoweringObjectFile *createTLOF(X86TargetMachine &TM) { switch (TM.getSubtarget().TargetType) { default: llvm_unreachable("unknown subtarget type"); case X86Subtarget::isDarwin: - // FIXME: This is for an EH test. - if (EnableX86EHTest) { - if (TM.getSubtarget().is64Bit()) - return new X8664_test_MachoTargetObjectFile(); - else - return new X86_test_MachoTargetObjectFile(); - } + if (TM.getSubtarget().is64Bit()) + return new X8664_MachoTargetObjectFile(); + else + return new X86_MachoTargetObjectFile(); if (TM.getSubtarget().is64Bit()) return new X8664_MachoTargetObjectFile(); Modified: llvm/trunk/lib/Target/X86/X86TargetObjectFile.cpp URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Target/X86/X86TargetObjectFile.cpp?rev=98564&r1=98563&r2=98564&view=diff ============================================================================== --- llvm/trunk/lib/Target/X86/X86TargetObjectFile.cpp (original) +++ llvm/trunk/lib/Target/X86/X86TargetObjectFile.cpp Mon Mar 15 14:04:37 2010 @@ -12,12 +12,26 @@ #include "X86TargetMachine.h" #include "llvm/CodeGen/MachineModuleInfoImpls.h" #include "llvm/MC/MCContext.h" +#include "llvm/MC/MCSectionMachO.h" #include "llvm/Target/Mangler.h" #include "llvm/ADT/SmallString.h" #include "llvm/Support/Dwarf.h" using namespace llvm; using namespace dwarf; +void X86_MachoTargetObjectFile::Initialize(MCContext &Ctx, + const TargetMachine &TM) { + TargetLoweringObjectFileMachO::Initialize(Ctx, TM); + + // Exception Handling. + LSDASection = getMachOSection("__TEXT", "__gcc_except_tab", 0, + SectionKind::getReadOnlyWithRel()); +} + +unsigned X86_MachoTargetObjectFile::getTTypeEncoding() const { + return DW_EH_PE_indirect | DW_EH_PE_pcrel | DW_EH_PE_sdata4; +} + const MCExpr *X8664_MachoTargetObjectFile:: getExprForDwarfGlobalReference(const GlobalValue *GV, Mangler *Mang, MachineModuleInfo *MMI, unsigned Encoding, Modified: llvm/trunk/lib/Target/X86/X86TargetObjectFile.h URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Target/X86/X86TargetObjectFile.h?rev=98564&r1=98563&r2=98564&view=diff ============================================================================== --- llvm/trunk/lib/Target/X86/X86TargetObjectFile.h (original) +++ llvm/trunk/lib/Target/X86/X86TargetObjectFile.h Mon Mar 15 14:04:37 2010 @@ -17,11 +17,19 @@ namespace llvm { class X86TargetMachine; - /// X8664_MachoTargetObjectFile - This TLOF implementation is used for - /// Darwin/x86-64. - class X8664_MachoTargetObjectFile : public TargetLoweringObjectFileMachO { + /// X86_MachoTargetObjectFile - This TLOF implementation is used for Darwin + /// x86 variants. + class X86_MachoTargetObjectFile : public TargetLoweringObjectFileMachO { public: + virtual void Initialize(MCContext &Ctx, const TargetMachine &TM); + virtual unsigned getTTypeEncoding() const; + }; + + /// X8664_MachoTargetObjectFile - This TLOF implementation is used for Darwin + /// x86-64. + class X8664_MachoTargetObjectFile : public X86_MachoTargetObjectFile { + public: virtual const MCExpr * getExprForDwarfGlobalReference(const GlobalValue *GV, Mangler *Mang, MachineModuleInfo *MMI, unsigned Encoding, From dpatel at apple.com Mon Mar 15 14:05:47 2010 From: dpatel at apple.com (Devang Patel) Date: Mon, 15 Mar 2010 19:05:47 -0000 Subject: [llvm-commits] [llvm] r98565 - /llvm/trunk/lib/Transforms/Scalar/SimplifyCFGPass.cpp Message-ID: <20100315190547.11B952A6C12C@llvm.org> Author: dpatel Date: Mon Mar 15 14:05:46 2010 New Revision: 98565 URL: http://llvm.org/viewvc/llvm-project?rev=98565&view=rev Log: In "empty" bb, the return instruction may not be first instruction, if dbg value intrinsics are present in this bb. Use terminator to find return instructions. Modified: llvm/trunk/lib/Transforms/Scalar/SimplifyCFGPass.cpp Modified: llvm/trunk/lib/Transforms/Scalar/SimplifyCFGPass.cpp URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Transforms/Scalar/SimplifyCFGPass.cpp?rev=98565&r1=98564&r2=98565&view=diff ============================================================================== --- llvm/trunk/lib/Transforms/Scalar/SimplifyCFGPass.cpp (original) +++ llvm/trunk/lib/Transforms/Scalar/SimplifyCFGPass.cpp Mon Mar 15 14:05:46 2010 @@ -244,7 +244,7 @@ // If the canonical return block has no PHI node, create one now. PHINode *RetBlockPHI = dyn_cast(RetBlock->begin()); if (RetBlockPHI == 0) { - Value *InVal = cast(RetBlock->begin())->getOperand(0); + Value *InVal = cast(RetBlock->getTerminator())->getOperand(0); RetBlockPHI = PHINode::Create(Ret->getOperand(0)->getType(), "merge", &RetBlock->front()); From sabre at nondot.org Mon Mar 15 14:09:43 2010 From: sabre at nondot.org (Chris Lattner) Date: Mon, 15 Mar 2010 19:09:43 -0000 Subject: [llvm-commits] [llvm] r98566 - in /llvm/trunk: include/llvm/CodeGen/MachineModuleInfo.h lib/CodeGen/MachineModuleInfo.cpp test/CodeGen/X86/crash.ll Message-ID: <20100315190943.E151A2A6C12C@llvm.org> Author: lattner Date: Mon Mar 15 14:09:43 2010 New Revision: 98566 URL: http://llvm.org/viewvc/llvm-project?rev=98566&view=rev Log: Fix the case when a reference to an address taken BB is emitted in one function, then the BB is RAUW'd before the definition is emitted. There are still two cases not being handled, but this should improve us back to the situation before I touched anything. Modified: llvm/trunk/include/llvm/CodeGen/MachineModuleInfo.h llvm/trunk/lib/CodeGen/MachineModuleInfo.cpp llvm/trunk/test/CodeGen/X86/crash.ll Modified: llvm/trunk/include/llvm/CodeGen/MachineModuleInfo.h URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/CodeGen/MachineModuleInfo.h?rev=98566&r1=98565&r2=98566&view=diff ============================================================================== --- llvm/trunk/include/llvm/CodeGen/MachineModuleInfo.h (original) +++ llvm/trunk/include/llvm/CodeGen/MachineModuleInfo.h Mon Mar 15 14:09:43 2010 @@ -88,6 +88,8 @@ : LandingPadBlock(MBB), LandingPadLabel(0), Personality(0) {} }; +class MMIAddrLabelMap; + //===----------------------------------------------------------------------===// /// MachineModuleInfo - This class contains meta information specific to a /// module. Queries can be made by different debugging and exception handling @@ -142,7 +144,7 @@ /// AddrLabelSymbols - This map keeps track of which symbol is being used for /// the specified basic block's address of label. - DenseMap, MCSymbol*> AddrLabelSymbols; + MMIAddrLabelMap *AddrLabelSymbols; bool CallsEHReturn; bool CallsUnwindInit; Modified: llvm/trunk/lib/CodeGen/MachineModuleInfo.cpp URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/CodeGen/MachineModuleInfo.cpp?rev=98566&r1=98565&r2=98566&view=diff ============================================================================== --- llvm/trunk/lib/CodeGen/MachineModuleInfo.cpp (original) +++ llvm/trunk/lib/CodeGen/MachineModuleInfo.cpp Mon Mar 15 14:09:43 2010 @@ -36,6 +36,99 @@ // Out of line virtual method. MachineModuleInfoImpl::~MachineModuleInfoImpl() {} +namespace llvm { +class MMIAddrLabelMapCallbackPtr : CallbackVH { + MMIAddrLabelMap *Map; +public: + MMIAddrLabelMapCallbackPtr() : Map(0) {} + MMIAddrLabelMapCallbackPtr(Value *V) : CallbackVH(V), Map(0) {} + + void setMap(MMIAddrLabelMap *map) { Map = map; } + + virtual void deleted(); + virtual void allUsesReplacedWith(Value *V2); +}; + +class MMIAddrLabelMap { + MCContext &Context; + struct AddrLabelSymEntry { + MCSymbol *Sym; + unsigned Index; + }; + + DenseMap, AddrLabelSymEntry> AddrLabelSymbols; + + std::vector BBCallbacks; +public: + + MMIAddrLabelMap(MCContext &context) : Context(context) {} + + MCSymbol *getAddrLabelSymbol(BasicBlock *BB); + void UpdateForDeletedBlock(BasicBlock *BB); + void UpdateForRAUWBlock(BasicBlock *Old, BasicBlock *New); +}; +} + +MCSymbol *MMIAddrLabelMap::getAddrLabelSymbol(BasicBlock *BB) { + assert(BB->hasAddressTaken() && + "Shouldn't get label for block without address taken"); + AddrLabelSymEntry &Entry = AddrLabelSymbols[BB]; + + // If we already had an entry for this block, just return it. + if (Entry.Sym) return Entry.Sym; + + // Otherwise, this is a new entry, create a new symbol for it and add an + // entry to BBCallbacks so we can be notified if the BB is deleted or RAUWd. + BBCallbacks.push_back(BB); + BBCallbacks.back().setMap(this); + Entry.Index = BBCallbacks.size()-1; + return Entry.Sym = Context.CreateTempSymbol(); +} + +void MMIAddrLabelMap::UpdateForDeletedBlock(BasicBlock *BB) { + // If the block got deleted, there is no need for the symbol. If the symbol + // was already emitted, we can just forget about it, otherwise we need to + // queue it up for later emission when the function is output. + AddrLabelSymEntry Entry = AddrLabelSymbols[BB]; + AddrLabelSymbols.erase(BB); + assert(Entry.Sym && "Didn't have a symbol, why a callback?"); + BBCallbacks[Entry.Index] = 0; // Clear the callback. + + if (Entry.Sym->isDefined()) + return; + + // If the block is not yet defined, we need to emit it at the end of the + // function. + assert(0 && "Case not handled yet!"); + abort(); +} + +void MMIAddrLabelMap::UpdateForRAUWBlock(BasicBlock *Old, BasicBlock *New) { + // Get the entry for the RAUW'd block and remove it from our map. + AddrLabelSymEntry OldEntry = AddrLabelSymbols[Old]; + AddrLabelSymbols.erase(Old); + assert(OldEntry.Sym && "Didn't have a symbol, why a callback?"); + + // If New is not address taken, just move our symbol over to it. + if (!AddrLabelSymbols.count(New)) { + BBCallbacks[OldEntry.Index] = New; // Update the callback. + AddrLabelSymbols[New] = OldEntry; // Set New's entry. + } else { + assert(0 && "Case not handled yet!"); + abort(); + } +} + + +void MMIAddrLabelMapCallbackPtr::deleted() { + Map->UpdateForDeletedBlock(cast(getValPtr())); +} + +void MMIAddrLabelMapCallbackPtr::allUsesReplacedWith(Value *V2) { + Map->UpdateForRAUWBlock(cast(getValPtr()), cast(V2)); +} + + //===----------------------------------------------------------------------===// MachineModuleInfo::MachineModuleInfo(const MCAsmInfo &MAI) @@ -44,6 +137,7 @@ CurCallSite(0), CallsEHReturn(0), CallsUnwindInit(0), DbgInfoAvailable(false){ // Always emit some info, by default "no personality" info. Personalities.push_back(NULL); + AddrLabelSymbols = 0; } MachineModuleInfo::MachineModuleInfo() @@ -55,17 +149,25 @@ MachineModuleInfo::~MachineModuleInfo() { delete ObjFileMMI; + + // FIXME: Why isn't doFinalization being called?? + //assert(AddrLabelSymbols == 0 && "doFinalization not called"); + delete AddrLabelSymbols; + AddrLabelSymbols = 0; } /// doInitialization - Initialize the state for a new module. /// bool MachineModuleInfo::doInitialization() { + assert(AddrLabelSymbols == 0 && "Improperly initialized"); return false; } /// doFinalization - Tear down the state after completion of a module. /// bool MachineModuleInfo::doFinalization() { + delete AddrLabelSymbols; + AddrLabelSymbols = 0; return false; } @@ -104,19 +206,21 @@ UsedFunctions.insert(F); } +//===- Address of Block Management ----------------------------------------===// + + /// getAddrLabelSymbol - Return the symbol to be used for the specified basic /// block when its address is taken. This cannot be its normal LBB label /// because the block may be accessed outside its containing function. MCSymbol *MachineModuleInfo::getAddrLabelSymbol(const BasicBlock *BB) { - assert(BB->hasAddressTaken() && - "Shouldn't get label for block without address taken"); - MCSymbol *&Entry = AddrLabelSymbols[const_cast(BB)]; - if (Entry) return Entry; - return Entry = Context.CreateTempSymbol(); + // Lazily create AddrLabelSymbols. + if (AddrLabelSymbols == 0) + AddrLabelSymbols = new MMIAddrLabelMap(Context); + return AddrLabelSymbols->getAddrLabelSymbol(const_cast(BB)); } -//===-EH-------------------------------------------------------------------===// +//===- EH -----------------------------------------------------------------===// /// getOrCreateLandingPadInfo - Find or create an LandingPadInfo for the /// specified MachineBasicBlock. Modified: llvm/trunk/test/CodeGen/X86/crash.ll URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/CodeGen/X86/crash.ll?rev=98566&r1=98565&r2=98566&view=diff ============================================================================== --- llvm/trunk/test/CodeGen/X86/crash.ll (original) +++ llvm/trunk/test/CodeGen/X86/crash.ll Mon Mar 15 14:09:43 2010 @@ -90,3 +90,28 @@ store i8 %8, i8* undef, align 1 ret void } + + +;; Issues with referring to a label that gets RAUW'd later. +define i32 @test6a() nounwind { +entry: + %target = bitcast i8* blockaddress(@test6b, %test_label) to i8* + + call i32 @test6b(i8* %target) + + ret i32 0 +} + +define i32 @test6b(i8* %target) nounwind { +entry: + indirectbr i8* %target, [label %test_label] + +test_label: +; assume some code here... + br label %ret + +ret: + ret i32 -1 +} + + From dpatel at apple.com Mon Mar 15 14:15:44 2010 From: dpatel at apple.com (Devang Patel) Date: Mon, 15 Mar 2010 19:15:44 -0000 Subject: [llvm-commits] [llvm] r98568 - /llvm/trunk/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp Message-ID: <20100315191544.932742A6C12C@llvm.org> Author: dpatel Date: Mon Mar 15 14:15:44 2010 New Revision: 98568 URL: http://llvm.org/viewvc/llvm-project?rev=98568&view=rev Log: Create SDDbgValue for dbg_value intrinsics and remember its connections with DAG nodes. This is a work in progress. Patch by Dale Johannesen! Modified: llvm/trunk/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp Modified: llvm/trunk/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp?rev=98568&r1=98567&r2=98568&view=diff ============================================================================== --- llvm/trunk/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp (original) +++ llvm/trunk/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp Mon Mar 15 14:15:44 2010 @@ -12,6 +12,7 @@ //===----------------------------------------------------------------------===// #define DEBUG_TYPE "isel" +#include "SDNodeDbgValue.h" #include "SelectionDAGBuilder.h" #include "FunctionLoweringInfo.h" #include "llvm/ADT/BitVector.h" @@ -3800,11 +3801,6 @@ return 0; } case Intrinsic::dbg_value: { - // FIXME: currently, we get here only if OptLevel != CodeGenOpt::None. - // The real handling of this intrinsic is in FastISel. - if (OptLevel != CodeGenOpt::None) - // FIXME: Variable debug info is not supported here. - return 0; DwarfWriter *DW = DAG.getDwarfWriter(); if (!DW) return 0; @@ -3813,9 +3809,36 @@ return 0; MDNode *Variable = DI.getVariable(); + uint64_t Offset = DI.getOffset(); Value *V = DI.getValue(); if (!V) return 0; + + // Build an entry in DbgOrdering. Debug info input nodes get an SDNodeOrder + // but do not always have a corresponding SDNode built. The SDNodeOrder + // absolute, but not relative, values are different depending on whether + // debug info exists. + ++SDNodeOrder; + if (isa(V) || isa(V)) { + SDDbgValue* dv = new SDDbgValue(Variable, V, Offset, dl, SDNodeOrder); + DAG.RememberDbgInfo(dv); + } else { + SDValue &N = NodeMap[V]; + if (N.getNode()) { + SDDbgValue *dv = new SDDbgValue(Variable, N.getNode(), + N.getResNo(), Offset, dl, SDNodeOrder); + DAG.AssignDbgInfo(N.getNode(), dv); + } else { + // We may expand this to cover more cases. One case where we have no + // data available is an unreferenced parameter; we need this fallback. + SDDbgValue* dv = new SDDbgValue(Variable, + UndefValue::get(V->getType()), + Offset, dl, SDNodeOrder); + DAG.RememberDbgInfo(dv); + } + } + + // Build a debug info table entry. if (BitCastInst *BCI = dyn_cast(V)) V = BCI->getOperand(0); AllocaInst *AI = dyn_cast(V); From clattner at apple.com Mon Mar 15 14:54:18 2010 From: clattner at apple.com (Chris Lattner) Date: Mon, 15 Mar 2010 12:54:18 -0700 Subject: [llvm-commits] [llvm] r98564 - in /llvm/trunk/lib/Target/X86: X86ISelLowering.cpp X86TargetObjectFile.cpp X86TargetObjectFile.h In-Reply-To: <20100315190439.D26CC2A6C12C@llvm.org> References: <20100315190439.D26CC2A6C12C@llvm.org> Message-ID: great! Can this move up to TargetLoweringObjectFileMachO now? -Chris On Mar 15, 2010, at 12:04 PM, Bill Wendling wrote: > Author: void > Date: Mon Mar 15 14:04:37 2010 > New Revision: 98564 > > URL: http://llvm.org/viewvc/llvm-project?rev=98564&view=rev > Log: > Place the LSDA into the TEXT section for x86 Darwin. If the global it's pointing > to is local to the translation unit, we need to place fill the value of that > symbol into the non-lazy pointer. > > This should conclude all Darwin changes for placing the LSDA into the TEXT > section. There is some cleanup to do. I.e., there's no longer a special need for > target-specific code here. But that can come later. > > Modified: > llvm/trunk/lib/Target/X86/X86ISelLowering.cpp > llvm/trunk/lib/Target/X86/X86TargetObjectFile.cpp > llvm/trunk/lib/Target/X86/X86TargetObjectFile.h > > Modified: llvm/trunk/lib/Target/X86/X86ISelLowering.cpp > URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Target/X86/X86ISelLowering.cpp?rev=98564&r1=98563&r2=98564&view=diff > ============================================================================== > --- llvm/trunk/lib/Target/X86/X86ISelLowering.cpp (original) > +++ llvm/trunk/lib/Target/X86/X86ISelLowering.cpp Mon Mar 15 14:04:37 2010 > @@ -70,53 +70,14 @@ > static SDValue getMOVL(SelectionDAG &DAG, DebugLoc dl, EVT VT, SDValue V1, > SDValue V2); > > -// FIXME: This is for a test. > -static cl::opt > -EnableX86EHTest("enable-x86-eh-test", cl::Hidden); > - > -namespace llvm { > - class X86_test_MachoTargetObjectFile : public TargetLoweringObjectFileMachO { > - public: > - virtual void Initialize(MCContext &Ctx, const TargetMachine &TM) { > - TargetLoweringObjectFileMachO::Initialize(Ctx, TM); > - > - // Exception Handling. > - LSDASection = getMachOSection("__TEXT", "__gcc_except_tab", 0, > - SectionKind::getReadOnlyWithRel()); > - } > - > - virtual unsigned getTTypeEncoding() const { > - return DW_EH_PE_indirect | DW_EH_PE_pcrel | DW_EH_PE_sdata4; > - } > - }; > - > - class X8664_test_MachoTargetObjectFile : public X8664_MachoTargetObjectFile { > - public: > - virtual void Initialize(MCContext &Ctx, const TargetMachine &TM) { > - TargetLoweringObjectFileMachO::Initialize(Ctx, TM); > - > - // Exception Handling. > - LSDASection = getMachOSection("__TEXT", "__gcc_except_tab", 0, > - SectionKind::getReadOnlyWithRel()); > - } > - > - virtual unsigned getTTypeEncoding() const { > - return DW_EH_PE_indirect | DW_EH_PE_pcrel | DW_EH_PE_sdata4; > - } > - }; > -} > - > static TargetLoweringObjectFile *createTLOF(X86TargetMachine &TM) { > switch (TM.getSubtarget().TargetType) { > default: llvm_unreachable("unknown subtarget type"); > case X86Subtarget::isDarwin: > - // FIXME: This is for an EH test. > - if (EnableX86EHTest) { > - if (TM.getSubtarget().is64Bit()) > - return new X8664_test_MachoTargetObjectFile(); > - else > - return new X86_test_MachoTargetObjectFile(); > - } > + if (TM.getSubtarget().is64Bit()) > + return new X8664_MachoTargetObjectFile(); > + else > + return new X86_MachoTargetObjectFile(); > > if (TM.getSubtarget().is64Bit()) > return new X8664_MachoTargetObjectFile(); > > Modified: llvm/trunk/lib/Target/X86/X86TargetObjectFile.cpp > URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Target/X86/X86TargetObjectFile.cpp?rev=98564&r1=98563&r2=98564&view=diff > ============================================================================== > --- llvm/trunk/lib/Target/X86/X86TargetObjectFile.cpp (original) > +++ llvm/trunk/lib/Target/X86/X86TargetObjectFile.cpp Mon Mar 15 14:04:37 2010 > @@ -12,12 +12,26 @@ > #include "X86TargetMachine.h" > #include "llvm/CodeGen/MachineModuleInfoImpls.h" > #include "llvm/MC/MCContext.h" > +#include "llvm/MC/MCSectionMachO.h" > #include "llvm/Target/Mangler.h" > #include "llvm/ADT/SmallString.h" > #include "llvm/Support/Dwarf.h" > using namespace llvm; > using namespace dwarf; > > +void X86_MachoTargetObjectFile::Initialize(MCContext &Ctx, > + const TargetMachine &TM) { > + TargetLoweringObjectFileMachO::Initialize(Ctx, TM); > + > + // Exception Handling. > + LSDASection = getMachOSection("__TEXT", "__gcc_except_tab", 0, > + SectionKind::getReadOnlyWithRel()); > +} > + > +unsigned X86_MachoTargetObjectFile::getTTypeEncoding() const { > + return DW_EH_PE_indirect | DW_EH_PE_pcrel | DW_EH_PE_sdata4; > +} > + > const MCExpr *X8664_MachoTargetObjectFile:: > getExprForDwarfGlobalReference(const GlobalValue *GV, Mangler *Mang, > MachineModuleInfo *MMI, unsigned Encoding, > > Modified: llvm/trunk/lib/Target/X86/X86TargetObjectFile.h > URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Target/X86/X86TargetObjectFile.h?rev=98564&r1=98563&r2=98564&view=diff > ============================================================================== > --- llvm/trunk/lib/Target/X86/X86TargetObjectFile.h (original) > +++ llvm/trunk/lib/Target/X86/X86TargetObjectFile.h Mon Mar 15 14:04:37 2010 > @@ -17,11 +17,19 @@ > namespace llvm { > class X86TargetMachine; > > - /// X8664_MachoTargetObjectFile - This TLOF implementation is used for > - /// Darwin/x86-64. > - class X8664_MachoTargetObjectFile : public TargetLoweringObjectFileMachO { > + /// X86_MachoTargetObjectFile - This TLOF implementation is used for Darwin > + /// x86 variants. > + class X86_MachoTargetObjectFile : public TargetLoweringObjectFileMachO { > public: > + virtual void Initialize(MCContext &Ctx, const TargetMachine &TM); > > + virtual unsigned getTTypeEncoding() const; > + }; > + > + /// X8664_MachoTargetObjectFile - This TLOF implementation is used for Darwin > + /// x86-64. > + class X8664_MachoTargetObjectFile : public X86_MachoTargetObjectFile { > + public: > virtual const MCExpr * > getExprForDwarfGlobalReference(const GlobalValue *GV, Mangler *Mang, > MachineModuleInfo *MMI, unsigned Encoding, > > > _______________________________________________ > llvm-commits mailing list > llvm-commits at cs.uiuc.edu > http://lists.cs.uiuc.edu/mailman/listinfo/llvm-commits From dgregor at apple.com Mon Mar 15 15:32:14 2010 From: dgregor at apple.com (Douglas Gregor) Date: Mon, 15 Mar 2010 20:32:14 -0000 Subject: [llvm-commits] [llvm] r98575 - in /llvm/trunk: include/llvm/Support/MemoryBuffer.h lib/Support/MemoryBuffer.cpp Message-ID: <20100315203214.2FA432A6C12C@llvm.org> Author: dgregor Date: Mon Mar 15 15:32:14 2010 New Revision: 98575 URL: http://llvm.org/viewvc/llvm-project?rev=98575&view=rev Log: Extend MemoryBuffer::getFile() to take an optional "stat" structure pointer. If given, the structure will be set with the stat information from the file actually read. Modified: llvm/trunk/include/llvm/Support/MemoryBuffer.h llvm/trunk/lib/Support/MemoryBuffer.cpp Modified: llvm/trunk/include/llvm/Support/MemoryBuffer.h URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/Support/MemoryBuffer.h?rev=98575&r1=98574&r2=98575&view=diff ============================================================================== --- llvm/trunk/include/llvm/Support/MemoryBuffer.h (original) +++ llvm/trunk/include/llvm/Support/MemoryBuffer.h Mon Mar 15 15:32:14 2010 @@ -17,6 +17,7 @@ #include "llvm/ADT/StringRef.h" #include "llvm/System/DataTypes.h" #include +#include namespace llvm { @@ -59,7 +60,8 @@ /// it has the specified size. static MemoryBuffer *getFile(StringRef Filename, std::string *ErrStr = 0, - int64_t FileSize = -1); + int64_t FileSize = -1, + struct stat *FileInfo = 0); /// getMemBuffer - Open the specified memory range as a MemoryBuffer. Note /// that EndPtr[0] must be a null byte and be accessible! @@ -95,7 +97,8 @@ /// in *ErrStr with a reason. static MemoryBuffer *getFileOrSTDIN(StringRef Filename, std::string *ErrStr = 0, - int64_t FileSize = -1); + int64_t FileSize = -1, + struct stat *FileInfo = 0); }; } // end namespace llvm Modified: llvm/trunk/lib/Support/MemoryBuffer.cpp URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Support/MemoryBuffer.cpp?rev=98575&r1=98574&r2=98575&view=diff ============================================================================== --- llvm/trunk/lib/Support/MemoryBuffer.cpp (original) +++ llvm/trunk/lib/Support/MemoryBuffer.cpp Mon Mar 15 15:32:14 2010 @@ -136,10 +136,11 @@ /// returns an empty buffer. MemoryBuffer *MemoryBuffer::getFileOrSTDIN(StringRef Filename, std::string *ErrStr, - int64_t FileSize) { + int64_t FileSize, + struct stat *FileInfo) { if (Filename == "-") return getSTDIN(); - return getFile(Filename, ErrStr, FileSize); + return getFile(Filename, ErrStr, FileSize, FileInfo); } //===----------------------------------------------------------------------===// @@ -169,7 +170,7 @@ } MemoryBuffer *MemoryBuffer::getFile(StringRef Filename, std::string *ErrStr, - int64_t FileSize) { + int64_t FileSize, struct stat *FileInfo) { int OpenFlags = 0; #ifdef O_BINARY OpenFlags |= O_BINARY; // Open input file in binary mode on win32. @@ -183,15 +184,17 @@ // If we don't know the file size, use fstat to find out. fstat on an open // file descriptor is cheaper than stat on a random path. - if (FileSize == -1) { - struct stat FileInfo; + if (FileSize == -1 || FileInfo) { + struct stat MyFileInfo; + struct stat *FileInfoPtr = FileInfo? FileInfo : &MyFileInfo; + // TODO: This should use fstat64 when available. - if (fstat(FD, &FileInfo) == -1) { + if (fstat(FD, FileInfoPtr) == -1) { if (ErrStr) *ErrStr = strerror(errno); ::close(FD); return 0; } - FileSize = FileInfo.st_size; + FileSize = FileInfoPtr->st_size; } From sabre at nondot.org Mon Mar 15 15:37:39 2010 From: sabre at nondot.org (Chris Lattner) Date: Mon, 15 Mar 2010 20:37:39 -0000 Subject: [llvm-commits] [llvm] r98577 - /llvm/trunk/lib/CodeGen/TargetLoweringObjectFileImpl.cpp Message-ID: <20100315203739.231312A6C12C@llvm.org> Author: lattner Date: Mon Mar 15 15:37:38 2010 New Revision: 98577 URL: http://llvm.org/viewvc/llvm-project?rev=98577&view=rev Log: use Mang->getSymbol() more. Modified: llvm/trunk/lib/CodeGen/TargetLoweringObjectFileImpl.cpp Modified: llvm/trunk/lib/CodeGen/TargetLoweringObjectFileImpl.cpp URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/CodeGen/TargetLoweringObjectFileImpl.cpp?rev=98577&r1=98576&r2=98577&view=diff ============================================================================== --- llvm/trunk/lib/CodeGen/TargetLoweringObjectFileImpl.cpp (original) +++ llvm/trunk/lib/CodeGen/TargetLoweringObjectFileImpl.cpp Mon Mar 15 15:37:38 2010 @@ -308,9 +308,9 @@ // into a 'uniqued' section name, create and return the section now. if (GV->isWeakForLinker() && !Kind.isCommon() && !Kind.isBSS()) { const char *Prefix = getSectionPrefixForUniqueGlobal(Kind); - SmallString<128> Name; - Name.append(Prefix, Prefix+strlen(Prefix)); - Mang->getNameWithPrefix(Name, GV, false); + SmallString<128> Name(Prefix, Prefix+strlen(Prefix)); + MCSymbol *Sym = Mang->getSymbol(GV); + Name.append(Sym->getName().begin(), Sym->getName().end()); return getELFSection(Name.str(), getELFSectionType(Name.str(), Kind), getELFSectionFlags(Kind), Kind); } @@ -406,24 +406,15 @@ // Add information about the stub reference to ELFMMI so that the stub // gets emitted by the asmprinter. - MCSymbol *Sym = getContext().GetOrCreateTemporarySymbol(Name.str()); - MachineModuleInfoImpl::StubValueTy &StubSym = ELFMMI.getGVStubEntry(Sym); + MCSymbol *SSym = getContext().GetOrCreateTemporarySymbol(Name.str()); + MachineModuleInfoImpl::StubValueTy &StubSym = ELFMMI.getGVStubEntry(SSym); if (StubSym.getPointer() == 0) { - Name.clear(); - Mang->getNameWithPrefix(Name, GV, false); - - if (GV->hasPrivateLinkage()) - StubSym = MachineModuleInfoImpl:: - StubValueTy(getContext().GetOrCreateTemporarySymbol(Name.str()), - false); - else - StubSym = MachineModuleInfoImpl:: - StubValueTy(getContext().GetOrCreateSymbol(Name.str()), - !GV->hasInternalLinkage()); + MCSymbol *Sym = Mang->getSymbol(GV); + StubSym = MachineModuleInfoImpl::StubValueTy(Sym, !GV->hasLocalLinkage()); } return TargetLoweringObjectFile:: - getExprForDwarfReference(Sym, Mang, MMI, + getExprForDwarfReference(SSym, Mang, MMI, Encoding & ~dwarf::DW_EH_PE_indirect, Streamer); } @@ -744,9 +735,8 @@ // FIXME: ObjC metadata is currently emitted as internal symbols that have // \1L and \0l prefixes on them. Fix them to be Private/LinkerPrivate and // this horrible hack can go away. - SmallString<64> Name; - Mang->getNameWithPrefix(Name, GV, false); - if (Name[0] == 'L' || Name[0] == 'l') + MCSymbol *Sym = Mang->getSymbol(GV); + if (Sym->getName()[0] == 'L' || Sym->getName()[0] == 'l') return false; } @@ -769,24 +759,15 @@ // Add information about the stub reference to MachOMMI so that the stub // gets emitted by the asmprinter. - MCSymbol *Sym = getContext().GetOrCreateTemporarySymbol(Name.str()); - MachineModuleInfoImpl::StubValueTy &StubSym = MachOMMI.getGVStubEntry(Sym); + MCSymbol *SSym = getContext().GetOrCreateTemporarySymbol(Name.str()); + MachineModuleInfoImpl::StubValueTy &StubSym = MachOMMI.getGVStubEntry(SSym); if (StubSym.getPointer() == 0) { - Name.clear(); - Mang->getNameWithPrefix(Name, GV, false); - - if (GV->hasPrivateLinkage()) - StubSym = MachineModuleInfoImpl:: - StubValueTy(getContext().GetOrCreateTemporarySymbol(Name.str()), - false); - else - StubSym = MachineModuleInfoImpl:: - StubValueTy(getContext().GetOrCreateSymbol(Name.str()), - !GV->hasInternalLinkage()); + MCSymbol *Sym = Mang->getSymbol(GV); + StubSym = MachineModuleInfoImpl::StubValueTy(Sym, !GV->hasLocalLinkage()); } return TargetLoweringObjectFile:: - getExprForDwarfReference(Sym, Mang, MMI, + getExprForDwarfReference(SSym, Mang, MMI, Encoding & ~dwarf::DW_EH_PE_indirect, Streamer); } @@ -918,7 +899,8 @@ if (GV->isWeakForLinker()) { const char *Prefix = getCOFFSectionPrefixForUniqueGlobal(Kind); SmallString<128> Name(Prefix, Prefix+strlen(Prefix)); - Mang->getNameWithPrefix(Name, GV, false); + MCSymbol *Sym = Mang->getSymbol(GV); + Name.append(Sym->getName().begin(), Sym->getName().end()); return getCOFFSection(Name.str(), false, Kind); } From sabre at nondot.org Mon Mar 15 15:37:58 2010 From: sabre at nondot.org (Chris Lattner) Date: Mon, 15 Mar 2010 20:37:58 -0000 Subject: [llvm-commits] [llvm] r98578 - /llvm/trunk/lib/Target/X86/X86TargetObjectFile.cpp Message-ID: <20100315203758.200402A6C12C@llvm.org> Author: lattner Date: Mon Mar 15 15:37:57 2010 New Revision: 98578 URL: http://llvm.org/viewvc/llvm-project?rev=98578&view=rev Log: use Mang->getSymbol() Modified: llvm/trunk/lib/Target/X86/X86TargetObjectFile.cpp Modified: llvm/trunk/lib/Target/X86/X86TargetObjectFile.cpp URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Target/X86/X86TargetObjectFile.cpp?rev=98578&r1=98577&r2=98578&view=diff ============================================================================== --- llvm/trunk/lib/Target/X86/X86TargetObjectFile.cpp (original) +++ llvm/trunk/lib/Target/X86/X86TargetObjectFile.cpp Mon Mar 15 15:37:57 2010 @@ -40,13 +40,7 @@ // On Darwin/X86-64, we can reference dwarf symbols with foo at GOTPCREL+4, which // is an indirect pc-relative reference. if (Encoding & (DW_EH_PE_indirect | DW_EH_PE_pcrel)) { - SmallString<128> Name; - Mang->getNameWithPrefix(Name, GV, false); - const MCSymbol *Sym; - if (GV->hasPrivateLinkage()) - Sym = getContext().GetOrCreateTemporarySymbol(Name); - else - Sym = getContext().GetOrCreateSymbol(Name); + const MCSymbol *Sym = Mang->getSymbol(GV); const MCExpr *Res = X86MCTargetExpr::Create(Sym, X86MCTargetExpr::GOTPCREL, getContext()); const MCExpr *Four = MCConstantExpr::Create(4, getContext()); From sabre at nondot.org Mon Mar 15 15:39:01 2010 From: sabre at nondot.org (Chris Lattner) Date: Mon, 15 Mar 2010 20:39:01 -0000 Subject: [llvm-commits] [llvm] r98579 - in /llvm/trunk: include/llvm/CodeGen/MachineModuleInfo.h lib/CodeGen/AsmPrinter/AsmPrinter.cpp lib/CodeGen/MachineModuleInfo.cpp test/CodeGen/Generic/addr-label.ll test/CodeGen/X86/crash.ll Message-ID: <20100315203901.17F902A6C12C@llvm.org> Author: lattner Date: Mon Mar 15 15:39:00 2010 New Revision: 98579 URL: http://llvm.org/viewvc/llvm-project?rev=98579&view=rev Log: Implement support for the case when a reference to a addr-of-bb label is generated, but then the block is deleted. Since the value is undefined, we just emit the label right after the entry label of the function. It might matter that the label is in the same section as the function was afterall. Added: llvm/trunk/test/CodeGen/Generic/addr-label.ll Modified: llvm/trunk/include/llvm/CodeGen/MachineModuleInfo.h llvm/trunk/lib/CodeGen/AsmPrinter/AsmPrinter.cpp llvm/trunk/lib/CodeGen/MachineModuleInfo.cpp llvm/trunk/test/CodeGen/X86/crash.ll Modified: llvm/trunk/include/llvm/CodeGen/MachineModuleInfo.h URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/CodeGen/MachineModuleInfo.h?rev=98579&r1=98578&r2=98579&view=diff ============================================================================== --- llvm/trunk/include/llvm/CodeGen/MachineModuleInfo.h (original) +++ llvm/trunk/include/llvm/CodeGen/MachineModuleInfo.h Mon Mar 15 15:39:00 2010 @@ -214,6 +214,14 @@ /// block when its address is taken. This cannot be its normal LBB label /// because the block may be accessed outside its containing function. MCSymbol *getAddrLabelSymbol(const BasicBlock *BB); + + /// takeDeletedSymbolsForFunction - If the specified function has had any + /// references to address-taken blocks generated, but the block got deleted, + /// return the symbol now so we can emit it. This prevents emitting a + /// reference to a symbol that has no definition. + void takeDeletedSymbolsForFunction(const Function *F, + std::vector &Result); + //===- EH ---------------------------------------------------------------===// Modified: llvm/trunk/lib/CodeGen/AsmPrinter/AsmPrinter.cpp URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/CodeGen/AsmPrinter/AsmPrinter.cpp?rev=98579&r1=98578&r2=98579&view=diff ============================================================================== --- llvm/trunk/lib/CodeGen/AsmPrinter/AsmPrinter.cpp (original) +++ llvm/trunk/lib/CodeGen/AsmPrinter/AsmPrinter.cpp Mon Mar 15 15:39:00 2010 @@ -307,6 +307,16 @@ // do their wild and crazy things as required. EmitFunctionEntryLabel(); + // If the function had address-taken blocks that got deleted, then we have + // references to the dangling symbols. Emit them at the start of the function + // so that we don't get references to undefined symbols. + std::vector DeadBlockSyms; + MMI->takeDeletedSymbolsForFunction(F, DeadBlockSyms); + for (unsigned i = 0, e = DeadBlockSyms.size(); i != e; ++i) { + OutStreamer.AddComment("Address taken block that was later removed"); + OutStreamer.EmitLabel(DeadBlockSyms[i]); + } + // Add some workaround for linkonce linkage on Cygwin\MinGW. if (MAI->getLinkOnceDirective() != 0 && (F->hasLinkOnceLinkage() || F->hasWeakLinkage())) Modified: llvm/trunk/lib/CodeGen/MachineModuleInfo.cpp URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/CodeGen/MachineModuleInfo.cpp?rev=98579&r1=98578&r2=98579&view=diff ============================================================================== --- llvm/trunk/lib/CodeGen/MachineModuleInfo.cpp (original) +++ llvm/trunk/lib/CodeGen/MachineModuleInfo.cpp Mon Mar 15 15:39:00 2010 @@ -52,18 +52,35 @@ class MMIAddrLabelMap { MCContext &Context; struct AddrLabelSymEntry { - MCSymbol *Sym; - unsigned Index; + MCSymbol *Sym; // The symbol for the label. + Function *Fn; // The containing function of the BasicBlock. + unsigned Index; // The index in BBCallbacks for the BasicBlock. }; DenseMap, AddrLabelSymEntry> AddrLabelSymbols; + /// BBCallbacks - Callbacks for the BasicBlock's that we have entries for. We + /// use this so we get notified if a block is deleted or RAUWd. std::vector BBCallbacks; + + /// DeletedAddrLabelsNeedingEmission - This is a per-function list of symbols + /// whose corresponding BasicBlock got deleted. These symbols need to be + /// emitted at some point in the file, so AsmPrinter emits them after the + /// function body. + DenseMap, std::vector > + DeletedAddrLabelsNeedingEmission; public: MMIAddrLabelMap(MCContext &context) : Context(context) {} + ~MMIAddrLabelMap() { + assert(DeletedAddrLabelsNeedingEmission.empty() && + "Some labels for deleted blocks never got emitted"); + } MCSymbol *getAddrLabelSymbol(BasicBlock *BB); + void takeDeletedSymbolsForFunction(Function *F, + std::vector &Result); + void UpdateForDeletedBlock(BasicBlock *BB); void UpdateForRAUWBlock(BasicBlock *Old, BasicBlock *New); }; @@ -75,16 +92,36 @@ AddrLabelSymEntry &Entry = AddrLabelSymbols[BB]; // If we already had an entry for this block, just return it. - if (Entry.Sym) return Entry.Sym; + if (Entry.Sym) { + assert(BB->getParent() == Entry.Fn && "Parent changed"); + return Entry.Sym; + } // Otherwise, this is a new entry, create a new symbol for it and add an // entry to BBCallbacks so we can be notified if the BB is deleted or RAUWd. BBCallbacks.push_back(BB); BBCallbacks.back().setMap(this); Entry.Index = BBCallbacks.size()-1; + Entry.Fn = BB->getParent(); return Entry.Sym = Context.CreateTempSymbol(); } +/// takeDeletedSymbolsForFunction - If we have any deleted symbols for F, return +/// them. +void MMIAddrLabelMap:: +takeDeletedSymbolsForFunction(Function *F, std::vector &Result) { + DenseMap, std::vector >::iterator I = + DeletedAddrLabelsNeedingEmission.find(F); + + // If there are no entries for the function, just return. + if (I == DeletedAddrLabelsNeedingEmission.end()) return; + + // Otherwise, take the list. + std::swap(Result, I->second); + DeletedAddrLabelsNeedingEmission.erase(I); +} + + void MMIAddrLabelMap::UpdateForDeletedBlock(BasicBlock *BB) { // If the block got deleted, there is no need for the symbol. If the symbol // was already emitted, we can just forget about it, otherwise we need to @@ -98,9 +135,13 @@ return; // If the block is not yet defined, we need to emit it at the end of the - // function. - assert(0 && "Case not handled yet!"); - abort(); + // function. Add the symbol to the DeletedAddrLabelsNeedingEmission list for + // the containing Function. Since the block is being deleted, its parent may + // already be removed, we have to get the function from 'Entry'. + assert((BB->getParent() == 0 || BB->getParent() == Entry.Fn) && + "Block/parent mismatch"); + + DeletedAddrLabelsNeedingEmission[Entry.Fn].push_back(Entry.Sym); } void MMIAddrLabelMap::UpdateForRAUWBlock(BasicBlock *Old, BasicBlock *New) { @@ -219,6 +260,18 @@ return AddrLabelSymbols->getAddrLabelSymbol(const_cast(BB)); } +/// takeDeletedSymbolsForFunction - If the specified function has had any +/// references to address-taken blocks generated, but the block got deleted, +/// return the symbol now so we can emit it. This prevents emitting a +/// reference to a symbol that has no definition. +void MachineModuleInfo:: +takeDeletedSymbolsForFunction(const Function *F, + std::vector &Result) { + // If no blocks have had their addresses taken, we're done. + if (AddrLabelSymbols == 0) return; + return AddrLabelSymbols-> + takeDeletedSymbolsForFunction(const_cast(F), Result); +} //===- EH -----------------------------------------------------------------===// Added: llvm/trunk/test/CodeGen/Generic/addr-label.ll URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/CodeGen/Generic/addr-label.ll?rev=98579&view=auto ============================================================================== --- llvm/trunk/test/CodeGen/Generic/addr-label.ll (added) +++ llvm/trunk/test/CodeGen/Generic/addr-label.ll Mon Mar 15 15:39:00 2010 @@ -0,0 +1,39 @@ +; RUN: llc %s -o - + +;; Reference to a label that gets deleted. +define i8* @test1() nounwind { +entry: + ret i8* blockaddress(@test1b, %test_label) +} + +define i32 @test1b() nounwind { +entry: + ret i32 -1 +test_label: + br label %ret +ret: + ret i32 -1 +} + + +;; Issues with referring to a label that gets RAUW'd later. +define i32 @test2a() nounwind { +entry: + %target = bitcast i8* blockaddress(@test2b, %test_label) to i8* + + call i32 @test2b(i8* %target) + + ret i32 0 +} + +define i32 @test2b(i8* %target) nounwind { +entry: + indirectbr i8* %target, [label %test_label] + +test_label: +; assume some code here... + br label %ret + +ret: + ret i32 -1 +} Modified: llvm/trunk/test/CodeGen/X86/crash.ll URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/CodeGen/X86/crash.ll?rev=98579&r1=98578&r2=98579&view=diff ============================================================================== --- llvm/trunk/test/CodeGen/X86/crash.ll (original) +++ llvm/trunk/test/CodeGen/X86/crash.ll Mon Mar 15 15:39:00 2010 @@ -92,26 +92,3 @@ } -;; Issues with referring to a label that gets RAUW'd later. -define i32 @test6a() nounwind { -entry: - %target = bitcast i8* blockaddress(@test6b, %test_label) to i8* - - call i32 @test6b(i8* %target) - - ret i32 0 -} - -define i32 @test6b(i8* %target) nounwind { -entry: - indirectbr i8* %target, [label %test_label] - -test_label: -; assume some code here... - br label %ret - -ret: - ret i32 -1 -} - - From isanbard at gmail.com Mon Mar 15 15:59:49 2010 From: isanbard at gmail.com (Bill Wendling) Date: Mon, 15 Mar 2010 13:59:49 -0700 Subject: [llvm-commits] [llvm] r98564 - in /llvm/trunk/lib/Target/X86: X86ISelLowering.cpp X86TargetObjectFile.cpp X86TargetObjectFile.h In-Reply-To: References: <20100315190439.D26CC2A6C12C@llvm.org> Message-ID: <53359391-A0B6-4EAE-806B-71D2E13D8292@gmail.com> Yes. :-) I'll clean it up later today. -bw On Mar 15, 2010, at 12:54 PM, Chris Lattner wrote: > great! Can this move up to TargetLoweringObjectFileMachO now? > > -Chris > > On Mar 15, 2010, at 12:04 PM, Bill Wendling wrote: > >> Author: void >> Date: Mon Mar 15 14:04:37 2010 >> New Revision: 98564 >> >> URL: http://llvm.org/viewvc/llvm-project?rev=98564&view=rev >> Log: >> Place the LSDA into the TEXT section for x86 Darwin. If the global it's pointing >> to is local to the translation unit, we need to place fill the value of that >> symbol into the non-lazy pointer. >> >> This should conclude all Darwin changes for placing the LSDA into the TEXT >> section. There is some cleanup to do. I.e., there's no longer a special need for >> target-specific code here. But that can come later. >> >> Modified: >> llvm/trunk/lib/Target/X86/X86ISelLowering.cpp >> llvm/trunk/lib/Target/X86/X86TargetObjectFile.cpp >> llvm/trunk/lib/Target/X86/X86TargetObjectFile.h >> >> Modified: llvm/trunk/lib/Target/X86/X86ISelLowering.cpp >> URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Target/X86/X86ISelLowering.cpp?rev=98564&r1=98563&r2=98564&view=diff >> ============================================================================== >> --- llvm/trunk/lib/Target/X86/X86ISelLowering.cpp (original) >> +++ llvm/trunk/lib/Target/X86/X86ISelLowering.cpp Mon Mar 15 14:04:37 2010 >> @@ -70,53 +70,14 @@ >> static SDValue getMOVL(SelectionDAG &DAG, DebugLoc dl, EVT VT, SDValue V1, >> SDValue V2); >> >> -// FIXME: This is for a test. >> -static cl::opt >> -EnableX86EHTest("enable-x86-eh-test", cl::Hidden); >> - >> -namespace llvm { >> - class X86_test_MachoTargetObjectFile : public TargetLoweringObjectFileMachO { >> - public: >> - virtual void Initialize(MCContext &Ctx, const TargetMachine &TM) { >> - TargetLoweringObjectFileMachO::Initialize(Ctx, TM); >> - >> - // Exception Handling. >> - LSDASection = getMachOSection("__TEXT", "__gcc_except_tab", 0, >> - SectionKind::getReadOnlyWithRel()); >> - } >> - >> - virtual unsigned getTTypeEncoding() const { >> - return DW_EH_PE_indirect | DW_EH_PE_pcrel | DW_EH_PE_sdata4; >> - } >> - }; >> - >> - class X8664_test_MachoTargetObjectFile : public X8664_MachoTargetObjectFile { >> - public: >> - virtual void Initialize(MCContext &Ctx, const TargetMachine &TM) { >> - TargetLoweringObjectFileMachO::Initialize(Ctx, TM); >> - >> - // Exception Handling. >> - LSDASection = getMachOSection("__TEXT", "__gcc_except_tab", 0, >> - SectionKind::getReadOnlyWithRel()); >> - } >> - >> - virtual unsigned getTTypeEncoding() const { >> - return DW_EH_PE_indirect | DW_EH_PE_pcrel | DW_EH_PE_sdata4; >> - } >> - }; >> -} >> - >> static TargetLoweringObjectFile *createTLOF(X86TargetMachine &TM) { >> switch (TM.getSubtarget().TargetType) { >> default: llvm_unreachable("unknown subtarget type"); >> case X86Subtarget::isDarwin: >> - // FIXME: This is for an EH test. >> - if (EnableX86EHTest) { >> - if (TM.getSubtarget().is64Bit()) >> - return new X8664_test_MachoTargetObjectFile(); >> - else >> - return new X86_test_MachoTargetObjectFile(); >> - } >> + if (TM.getSubtarget().is64Bit()) >> + return new X8664_MachoTargetObjectFile(); >> + else >> + return new X86_MachoTargetObjectFile(); >> >> if (TM.getSubtarget().is64Bit()) >> return new X8664_MachoTargetObjectFile(); >> >> Modified: llvm/trunk/lib/Target/X86/X86TargetObjectFile.cpp >> URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Target/X86/X86TargetObjectFile.cpp?rev=98564&r1=98563&r2=98564&view=diff >> ============================================================================== >> --- llvm/trunk/lib/Target/X86/X86TargetObjectFile.cpp (original) >> +++ llvm/trunk/lib/Target/X86/X86TargetObjectFile.cpp Mon Mar 15 14:04:37 2010 >> @@ -12,12 +12,26 @@ >> #include "X86TargetMachine.h" >> #include "llvm/CodeGen/MachineModuleInfoImpls.h" >> #include "llvm/MC/MCContext.h" >> +#include "llvm/MC/MCSectionMachO.h" >> #include "llvm/Target/Mangler.h" >> #include "llvm/ADT/SmallString.h" >> #include "llvm/Support/Dwarf.h" >> using namespace llvm; >> using namespace dwarf; >> >> +void X86_MachoTargetObjectFile::Initialize(MCContext &Ctx, >> + const TargetMachine &TM) { >> + TargetLoweringObjectFileMachO::Initialize(Ctx, TM); >> + >> + // Exception Handling. >> + LSDASection = getMachOSection("__TEXT", "__gcc_except_tab", 0, >> + SectionKind::getReadOnlyWithRel()); >> +} >> + >> +unsigned X86_MachoTargetObjectFile::getTTypeEncoding() const { >> + return DW_EH_PE_indirect | DW_EH_PE_pcrel | DW_EH_PE_sdata4; >> +} >> + >> const MCExpr *X8664_MachoTargetObjectFile:: >> getExprForDwarfGlobalReference(const GlobalValue *GV, Mangler *Mang, >> MachineModuleInfo *MMI, unsigned Encoding, >> >> Modified: llvm/trunk/lib/Target/X86/X86TargetObjectFile.h >> URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Target/X86/X86TargetObjectFile.h?rev=98564&r1=98563&r2=98564&view=diff >> ============================================================================== >> --- llvm/trunk/lib/Target/X86/X86TargetObjectFile.h (original) >> +++ llvm/trunk/lib/Target/X86/X86TargetObjectFile.h Mon Mar 15 14:04:37 2010 >> @@ -17,11 +17,19 @@ >> namespace llvm { >> class X86TargetMachine; >> >> - /// X8664_MachoTargetObjectFile - This TLOF implementation is used for >> - /// Darwin/x86-64. >> - class X8664_MachoTargetObjectFile : public TargetLoweringObjectFileMachO { >> + /// X86_MachoTargetObjectFile - This TLOF implementation is used for Darwin >> + /// x86 variants. >> + class X86_MachoTargetObjectFile : public TargetLoweringObjectFileMachO { >> public: >> + virtual void Initialize(MCContext &Ctx, const TargetMachine &TM); >> >> + virtual unsigned getTTypeEncoding() const; >> + }; >> + >> + /// X8664_MachoTargetObjectFile - This TLOF implementation is used for Darwin >> + /// x86-64. >> + class X8664_MachoTargetObjectFile : public X86_MachoTargetObjectFile { >> + public: >> virtual const MCExpr * >> getExprForDwarfGlobalReference(const GlobalValue *GV, Mangler *Mang, >> MachineModuleInfo *MMI, unsigned Encoding, >> >> >> _______________________________________________ >> llvm-commits mailing list >> llvm-commits at cs.uiuc.edu >> http://lists.cs.uiuc.edu/mailman/listinfo/llvm-commits > > > _______________________________________________ > llvm-commits mailing list > llvm-commits at cs.uiuc.edu > http://lists.cs.uiuc.edu/mailman/listinfo/llvm-commits From isanbard at gmail.com Mon Mar 15 16:09:39 2010 From: isanbard at gmail.com (Bill Wendling) Date: Mon, 15 Mar 2010 21:09:39 -0000 Subject: [llvm-commits] [llvm] r98580 - in /llvm/trunk/lib: CodeGen/TargetLoweringObjectFileImpl.cpp Target/ARM/ARMISelLowering.cpp Target/ARM/ARMTargetObjectFile.cpp Target/ARM/ARMTargetObjectFile.h Target/PowerPC/CMakeLists.txt Target/PowerPC/PPCISelLowering.cpp Target/PowerPC/PPCTargetObjectFile.cpp Target/PowerPC/PPCTargetObjectFile.h Target/X86/X86ISelLowering.cpp Target/X86/X86TargetObjectFile.cpp Target/X86/X86TargetObjectFile.h Message-ID: <20100315210939.86E3A2A6C12C@llvm.org> Author: void Date: Mon Mar 15 16:09:38 2010 New Revision: 98580 URL: http://llvm.org/viewvc/llvm-project?rev=98580&view=rev Log: Now that the default for Darwin platforms is to place the LSDA into the TEXT section, remove the target-specific code that performs this. Removed: llvm/trunk/lib/Target/PowerPC/PPCTargetObjectFile.cpp llvm/trunk/lib/Target/PowerPC/PPCTargetObjectFile.h Modified: llvm/trunk/lib/CodeGen/TargetLoweringObjectFileImpl.cpp llvm/trunk/lib/Target/ARM/ARMISelLowering.cpp llvm/trunk/lib/Target/ARM/ARMTargetObjectFile.cpp llvm/trunk/lib/Target/ARM/ARMTargetObjectFile.h llvm/trunk/lib/Target/PowerPC/CMakeLists.txt llvm/trunk/lib/Target/PowerPC/PPCISelLowering.cpp llvm/trunk/lib/Target/X86/X86ISelLowering.cpp llvm/trunk/lib/Target/X86/X86TargetObjectFile.cpp llvm/trunk/lib/Target/X86/X86TargetObjectFile.h Modified: llvm/trunk/lib/CodeGen/TargetLoweringObjectFileImpl.cpp URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/CodeGen/TargetLoweringObjectFileImpl.cpp?rev=98580&r1=98579&r2=98580&view=diff ============================================================================== --- llvm/trunk/lib/CodeGen/TargetLoweringObjectFileImpl.cpp (original) +++ llvm/trunk/lib/CodeGen/TargetLoweringObjectFileImpl.cpp Mon Mar 15 16:09:38 2010 @@ -560,8 +560,8 @@ } // Exception Handling. - LSDASection = getMachOSection("__DATA", "__gcc_except_tab", 0, - SectionKind::getDataRel()); + LSDASection = getMachOSection("__TEXT", "__gcc_except_tab", 0, + SectionKind::getReadOnlyWithRel()); EHFrameSection = getMachOSection("__TEXT", "__eh_frame", MCSectionMachO::S_COALESCED | @@ -788,7 +788,7 @@ } unsigned TargetLoweringObjectFileMachO::getTTypeEncoding() const { - return DW_EH_PE_absptr; + return DW_EH_PE_indirect | DW_EH_PE_pcrel | DW_EH_PE_sdata4; } //===----------------------------------------------------------------------===// Modified: llvm/trunk/lib/Target/ARM/ARMISelLowering.cpp URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Target/ARM/ARMISelLowering.cpp?rev=98580&r1=98579&r2=98580&view=diff ============================================================================== --- llvm/trunk/lib/Target/ARM/ARMISelLowering.cpp (original) +++ llvm/trunk/lib/Target/ARM/ARMISelLowering.cpp Mon Mar 15 16:09:38 2010 @@ -130,7 +130,7 @@ static TargetLoweringObjectFile *createTLOF(TargetMachine &TM) { if (TM.getSubtarget().isTargetDarwin()) - return new ARMMachOTargetObjectFile(); + return new TargetLoweringObjectFileMachO(); return new ARMElfTargetObjectFile(); } Modified: llvm/trunk/lib/Target/ARM/ARMTargetObjectFile.cpp URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Target/ARM/ARMTargetObjectFile.cpp?rev=98580&r1=98579&r2=98580&view=diff ============================================================================== --- llvm/trunk/lib/Target/ARM/ARMTargetObjectFile.cpp (original) +++ llvm/trunk/lib/Target/ARM/ARMTargetObjectFile.cpp Mon Mar 15 16:09:38 2010 @@ -10,7 +10,6 @@ #include "ARMTargetObjectFile.h" #include "ARMSubtarget.h" #include "llvm/MC/MCSectionELF.h" -#include "llvm/MC/MCSectionMachO.h" #include "llvm/Support/Dwarf.h" #include "llvm/Target/TargetMachine.h" using namespace llvm; @@ -35,20 +34,3 @@ SectionKind::getDataRel()); } } - -//===----------------------------------------------------------------------===// -// Mach-O Target -//===----------------------------------------------------------------------===// - -void ARMMachOTargetObjectFile::Initialize(MCContext &Ctx, - const TargetMachine &TM) { - TargetLoweringObjectFileMachO::Initialize(Ctx, TM); - - // Exception Handling. - LSDASection = getMachOSection("__TEXT", "__gcc_except_tab", 0, - SectionKind::getReadOnlyWithRel()); -} - -unsigned ARMMachOTargetObjectFile::getTTypeEncoding() const { - return DW_EH_PE_indirect | DW_EH_PE_pcrel | DW_EH_PE_sdata4; -} Modified: llvm/trunk/lib/Target/ARM/ARMTargetObjectFile.h URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Target/ARM/ARMTargetObjectFile.h?rev=98580&r1=98579&r2=98580&view=diff ============================================================================== --- llvm/trunk/lib/Target/ARM/ARMTargetObjectFile.h (original) +++ llvm/trunk/lib/Target/ARM/ARMTargetObjectFile.h Mon Mar 15 16:09:38 2010 @@ -24,18 +24,6 @@ virtual void Initialize(MCContext &Ctx, const TargetMachine &TM); }; -// FIXME: This subclass isn't 100% necessary. It will become obsolete once we -// can place all LSDAs into the TEXT section. See -// . -class ARMMachOTargetObjectFile : public TargetLoweringObjectFileMachO { -public: - ARMMachOTargetObjectFile() : TargetLoweringObjectFileMachO() {} - - virtual void Initialize(MCContext &Ctx, const TargetMachine &TM); - - virtual unsigned getTTypeEncoding() const; -}; - } // end namespace llvm #endif Modified: llvm/trunk/lib/Target/PowerPC/CMakeLists.txt URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Target/PowerPC/CMakeLists.txt?rev=98580&r1=98579&r2=98580&view=diff ============================================================================== --- llvm/trunk/lib/Target/PowerPC/CMakeLists.txt (original) +++ llvm/trunk/lib/Target/PowerPC/CMakeLists.txt Mon Mar 15 16:09:38 2010 @@ -24,7 +24,6 @@ PPCRegisterInfo.cpp PPCSubtarget.cpp PPCTargetMachine.cpp - PPCTargetObjectFile.cpp ) target_link_libraries (LLVMPowerPCCodeGen LLVMSelectionDAG) Modified: llvm/trunk/lib/Target/PowerPC/PPCISelLowering.cpp URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Target/PowerPC/PPCISelLowering.cpp?rev=98580&r1=98579&r2=98580&view=diff ============================================================================== --- llvm/trunk/lib/Target/PowerPC/PPCISelLowering.cpp (original) +++ llvm/trunk/lib/Target/PowerPC/PPCISelLowering.cpp Mon Mar 15 16:09:38 2010 @@ -16,7 +16,6 @@ #include "PPCPerfectShuffle.h" #include "PPCPredicates.h" #include "PPCTargetMachine.h" -#include "PPCTargetObjectFile.h" #include "llvm/ADT/STLExtras.h" #include "llvm/ADT/VectorExtras.h" #include "llvm/CodeGen/CallingConvLower.h" @@ -60,7 +59,7 @@ static TargetLoweringObjectFile *CreateTLOF(const PPCTargetMachine &TM) { if (TM.getSubtargetImpl()->isDarwin()) - return new PPCMachOTargetObjectFile(); + return new TargetLoweringObjectFileMachO(); return new TargetLoweringObjectFileELF(); } Removed: llvm/trunk/lib/Target/PowerPC/PPCTargetObjectFile.cpp URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Target/PowerPC/PPCTargetObjectFile.cpp?rev=98579&view=auto ============================================================================== --- llvm/trunk/lib/Target/PowerPC/PPCTargetObjectFile.cpp (original) +++ llvm/trunk/lib/Target/PowerPC/PPCTargetObjectFile.cpp (removed) @@ -1,33 +0,0 @@ -//===-- llvm/Target/PPCTargetObjectFile.cpp - PPC Object Info Impl --------===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// - -#include "PPCTargetObjectFile.h" -#include "PPCSubtarget.h" -#include "llvm/MC/MCSectionMachO.h" -#include "llvm/Support/Dwarf.h" -#include "llvm/Target/TargetMachine.h" -using namespace llvm; -using namespace dwarf; - -//===----------------------------------------------------------------------===// -// Mach-O Target -//===----------------------------------------------------------------------===// - -void PPCMachOTargetObjectFile::Initialize(MCContext &Ctx, - const TargetMachine &TM) { - TargetLoweringObjectFileMachO::Initialize(Ctx, TM); - - // Exception Handling. - LSDASection = getMachOSection("__TEXT", "__gcc_except_tab", 0, - SectionKind::getReadOnlyWithRel()); -} - -unsigned PPCMachOTargetObjectFile::getTTypeEncoding() const { - return DW_EH_PE_indirect | DW_EH_PE_pcrel | DW_EH_PE_sdata4; -} Removed: llvm/trunk/lib/Target/PowerPC/PPCTargetObjectFile.h URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Target/PowerPC/PPCTargetObjectFile.h?rev=98579&view=auto ============================================================================== --- llvm/trunk/lib/Target/PowerPC/PPCTargetObjectFile.h (original) +++ llvm/trunk/lib/Target/PowerPC/PPCTargetObjectFile.h (removed) @@ -1,34 +0,0 @@ -//===-- llvm/Target/PPCTargetObjectFile.h - PowerPC Object Info -*- C++ -*-===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// - -#ifndef LLVM_TARGET_PPC_TARGETOBJECTFILE_H -#define LLVM_TARGET_PPC_TARGETOBJECTFILE_H - -#include "llvm/CodeGen/TargetLoweringObjectFileImpl.h" - -namespace llvm { - -class MCContext; -class TargetMachine; - -// FIXME: This subclass isn't 100% necessary. It will become obsolete once we -// can place all LSDAs into the TEXT section. See -// . -class PPCMachOTargetObjectFile : public TargetLoweringObjectFileMachO { -public: - PPCMachOTargetObjectFile() : TargetLoweringObjectFileMachO() {} - - virtual void Initialize(MCContext &Ctx, const TargetMachine &TM); - - virtual unsigned getTTypeEncoding() const; -}; - -} // end namespace llvm - -#endif Modified: llvm/trunk/lib/Target/X86/X86ISelLowering.cpp URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Target/X86/X86ISelLowering.cpp?rev=98580&r1=98579&r2=98580&view=diff ============================================================================== --- llvm/trunk/lib/Target/X86/X86ISelLowering.cpp (original) +++ llvm/trunk/lib/Target/X86/X86ISelLowering.cpp Mon Mar 15 16:09:38 2010 @@ -37,7 +37,6 @@ #include "llvm/CodeGen/PseudoSourceValue.h" #include "llvm/MC/MCAsmInfo.h" #include "llvm/MC/MCContext.h" -#include "llvm/MC/MCSectionMachO.h" #include "llvm/MC/MCSymbol.h" #include "llvm/ADT/BitVector.h" #include "llvm/ADT/SmallSet.h" @@ -76,11 +75,6 @@ case X86Subtarget::isDarwin: if (TM.getSubtarget().is64Bit()) return new X8664_MachoTargetObjectFile(); - else - return new X86_MachoTargetObjectFile(); - - if (TM.getSubtarget().is64Bit()) - return new X8664_MachoTargetObjectFile(); return new TargetLoweringObjectFileMachO(); case X86Subtarget::isELF: if (TM.getSubtarget().is64Bit()) Modified: llvm/trunk/lib/Target/X86/X86TargetObjectFile.cpp URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Target/X86/X86TargetObjectFile.cpp?rev=98580&r1=98579&r2=98580&view=diff ============================================================================== --- llvm/trunk/lib/Target/X86/X86TargetObjectFile.cpp (original) +++ llvm/trunk/lib/Target/X86/X86TargetObjectFile.cpp Mon Mar 15 16:09:38 2010 @@ -19,19 +19,6 @@ using namespace llvm; using namespace dwarf; -void X86_MachoTargetObjectFile::Initialize(MCContext &Ctx, - const TargetMachine &TM) { - TargetLoweringObjectFileMachO::Initialize(Ctx, TM); - - // Exception Handling. - LSDASection = getMachOSection("__TEXT", "__gcc_except_tab", 0, - SectionKind::getReadOnlyWithRel()); -} - -unsigned X86_MachoTargetObjectFile::getTTypeEncoding() const { - return DW_EH_PE_indirect | DW_EH_PE_pcrel | DW_EH_PE_sdata4; -} - const MCExpr *X8664_MachoTargetObjectFile:: getExprForDwarfGlobalReference(const GlobalValue *GV, Mangler *Mang, MachineModuleInfo *MMI, unsigned Encoding, Modified: llvm/trunk/lib/Target/X86/X86TargetObjectFile.h URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Target/X86/X86TargetObjectFile.h?rev=98580&r1=98579&r2=98580&view=diff ============================================================================== --- llvm/trunk/lib/Target/X86/X86TargetObjectFile.h (original) +++ llvm/trunk/lib/Target/X86/X86TargetObjectFile.h Mon Mar 15 16:09:38 2010 @@ -17,18 +17,9 @@ namespace llvm { class X86TargetMachine; - /// X86_MachoTargetObjectFile - This TLOF implementation is used for Darwin - /// x86 variants. - class X86_MachoTargetObjectFile : public TargetLoweringObjectFileMachO { - public: - virtual void Initialize(MCContext &Ctx, const TargetMachine &TM); - - virtual unsigned getTTypeEncoding() const; - }; - /// X8664_MachoTargetObjectFile - This TLOF implementation is used for Darwin /// x86-64. - class X8664_MachoTargetObjectFile : public X86_MachoTargetObjectFile { + class X8664_MachoTargetObjectFile : public TargetLoweringObjectFileMachO { public: virtual const MCExpr * getExprForDwarfGlobalReference(const GlobalValue *GV, Mangler *Mang, From anton at korobeynikov.info Mon Mar 15 16:22:36 2010 From: anton at korobeynikov.info (Anton Korobeynikov) Date: Tue, 16 Mar 2010 00:22:36 +0300 Subject: [llvm-commits] [llvm] r98580 - in /llvm/trunk/lib: CodeGen/TargetLoweringObjectFileImpl.cpp Target/ARM/ARMISelLowering.cpp Target/ARM/ARMTargetObjectFile.cpp Target/ARM/ARMTargetObjectFile.h Target/PowerPC/CMakeLists.txt Target/PowerPC/PPCISelLow Message-ID: > URL: http://llvm.org/viewvc/llvm-project?rev=98580&view=rev > Log: > Now that the default for Darwin platforms is to place the LSDA into the TEXT > section, remove the target-specific code that performs this. Yay! Thanks, Bill -- With best regards, Anton Korobeynikov Faculty of Mathematics and Mechanics, Saint Petersburg State University From isanbard at gmail.com Mon Mar 15 16:23:36 2010 From: isanbard at gmail.com (Bill Wendling) Date: Mon, 15 Mar 2010 14:23:36 -0700 Subject: [llvm-commits] [llvm] r98580 - in /llvm/trunk/lib: CodeGen/TargetLoweringObjectFileImpl.cpp Target/ARM/ARMISelLowering.cpp Target/ARM/ARMTargetObjectFile.cpp Target/ARM/ARMTargetObjectFile.h Target/PowerPC/CMakeLists.txt Target/PowerPC/PPCISelLow In-Reply-To: References: Message-ID: <513F2AFA-A04E-4404-A2EA-E19D4F1DD993@gmail.com> On Mar 15, 2010, at 2:22 PM, Anton Korobeynikov wrote: >> URL: http://llvm.org/viewvc/llvm-project?rev=98580&view=rev >> Log: >> Now that the default for Darwin platforms is to place the LSDA into the TEXT >> section, remove the target-specific code that performs this. > Yay! Thanks, Bill > Of course! Now let's hope that this is the last time I have to do this. ;-) -bw From dpatel at apple.com Mon Mar 15 16:25:30 2010 From: dpatel at apple.com (Devang Patel) Date: Mon, 15 Mar 2010 21:25:30 -0000 Subject: [llvm-commits] [llvm] r98581 - /llvm/trunk/lib/Transforms/Utils/LoopSimplify.cpp Message-ID: <20100315212530.277DD2A6C12C@llvm.org> Author: dpatel Date: Mon Mar 15 16:25:29 2010 New Revision: 98581 URL: http://llvm.org/viewvc/llvm-project?rev=98581&view=rev Log: Skip debug info intrinsics. Modified: llvm/trunk/lib/Transforms/Utils/LoopSimplify.cpp Modified: llvm/trunk/lib/Transforms/Utils/LoopSimplify.cpp URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Transforms/Utils/LoopSimplify.cpp?rev=98581&r1=98580&r2=98581&view=diff ============================================================================== --- llvm/trunk/lib/Transforms/Utils/LoopSimplify.cpp (original) +++ llvm/trunk/lib/Transforms/Utils/LoopSimplify.cpp Mon Mar 15 16:25:29 2010 @@ -41,6 +41,7 @@ #include "llvm/Transforms/Scalar.h" #include "llvm/Constants.h" #include "llvm/Instructions.h" +#include "llvm/IntrinsicInst.h" #include "llvm/Function.h" #include "llvm/LLVMContext.h" #include "llvm/Type.h" @@ -290,6 +291,9 @@ bool AllInvariant = true; for (BasicBlock::iterator I = ExitingBlock->begin(); &*I != BI; ) { Instruction *Inst = I++; + // Skip debug info intrinsics. + if (isa(Inst)) + continue; if (Inst == CI) continue; if (!L->makeLoopInvariant(Inst, Changed, From anton at korobeynikov.info Mon Mar 15 16:27:38 2010 From: anton at korobeynikov.info (Anton Korobeynikov) Date: Tue, 16 Mar 2010 00:27:38 +0300 Subject: [llvm-commits] [llvm] r98580 - in /llvm/trunk/lib: CodeGen/TargetLoweringObjectFileImpl.cpp Target/ARM/ARMISelLowering.cpp Target/ARM/ARMTargetObjectFile.cpp Target/ARM/ARMTargetObjectFile.h Target/PowerPC/CMakeLists.txt Target/PowerPC/PPCISelLow In-Reply-To: <513F2AFA-A04E-4404-A2EA-E19D4F1DD993@gmail.com> References: <513F2AFA-A04E-4404-A2EA-E19D4F1DD993@gmail.com> Message-ID: > Of course! Now let's hope that this is the last time I have to do this. ;-) You don't like dwarf EH, do you? :) -- With best regards, Anton Korobeynikov Faculty of Mathematics and Mechanics, Saint Petersburg State University From isanbard at gmail.com Mon Mar 15 16:52:44 2010 From: isanbard at gmail.com (Bill Wendling) Date: Mon, 15 Mar 2010 14:52:44 -0700 Subject: [llvm-commits] [llvm] r98580 - in /llvm/trunk/lib: CodeGen/TargetLoweringObjectFileImpl.cpp Target/ARM/ARMISelLowering.cpp Target/ARM/ARMTargetObjectFile.cpp Target/ARM/ARMTargetObjectFile.h Target/PowerPC/CMakeLists.txt Target/PowerPC/PPCISelLow In-Reply-To: References: <513F2AFA-A04E-4404-A2EA-E19D4F1DD993@gmail.com> Message-ID: <9EEF8CF4-06F7-4E39-90E6-E8568BF95646@gmail.com> On Mar 15, 2010, at 2:27 PM, Anton Korobeynikov wrote: >> Of course! Now let's hope that this is the last time I have to do this. ;-) > You don't like dwarf EH, do you? :) > It's job security at least. ;-) -bw From daniel at zuster.org Mon Mar 15 16:56:38 2010 From: daniel at zuster.org (Daniel Dunbar) Date: Mon, 15 Mar 2010 21:56:38 -0000 Subject: [llvm-commits] [llvm] r98582 - in /llvm/trunk: include/llvm/MC/MCSectionMachO.h lib/MC/MCAssembler.cpp Message-ID: <20100315215638.930AF2A6C12C@llvm.org> Author: ddunbar Date: Mon Mar 15 16:56:38 2010 New Revision: 98582 URL: http://llvm.org/viewvc/llvm-project?rev=98582&view=rev Log: MC/Mach-O: Add MCSectionMachO::getType() Modified: llvm/trunk/include/llvm/MC/MCSectionMachO.h llvm/trunk/lib/MC/MCAssembler.cpp Modified: llvm/trunk/include/llvm/MC/MCSectionMachO.h URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/MC/MCSectionMachO.h?rev=98582&r1=98581&r2=98582&view=diff ============================================================================== --- llvm/trunk/include/llvm/MC/MCSectionMachO.h (original) +++ llvm/trunk/include/llvm/MC/MCSectionMachO.h Mon Mar 15 16:56:38 2010 @@ -151,10 +151,12 @@ return StringRef(SectionName, 16); return StringRef(SectionName); } - + unsigned getTypeAndAttributes() const { return TypeAndAttributes; } unsigned getStubSize() const { return Reserved2; } - + + unsigned getType() const { return TypeAndAttributes & SECTION_TYPE; } + /// ParseSectionSpecifier - Parse the section specifier indicated by "Spec". /// This is a string that can appear after a .section directive in a mach-o /// flavored .s file. If successful, this fills in the specified Out @@ -165,7 +167,7 @@ StringRef &Section, // Out. unsigned &TAA, // Out. unsigned &StubSize); // Out. - + virtual void PrintSwitchToSection(const MCAsmInfo &MAI, raw_ostream &OS) const; }; Modified: llvm/trunk/lib/MC/MCAssembler.cpp URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/MC/MCAssembler.cpp?rev=98582&r1=98581&r2=98582&view=diff ============================================================================== --- llvm/trunk/lib/MC/MCAssembler.cpp (original) +++ llvm/trunk/lib/MC/MCAssembler.cpp Mon Mar 15 16:56:38 2010 @@ -52,8 +52,7 @@ static bool isVirtualSection(const MCSection &Section) { // FIXME: Lame. const MCSectionMachO &SMO = static_cast(Section); - unsigned Type = SMO.getTypeAndAttributes() & MCSectionMachO::SECTION_TYPE; - return (Type == MCSectionMachO::S_ZEROFILL); + return (SMO.getType() == MCSectionMachO::S_ZEROFILL); } static unsigned getFixupKindLog2Size(unsigned Kind) { @@ -615,9 +614,7 @@ const MCSectionMachO &Section = static_cast(it->SectionData->getSection()); - unsigned Type = - Section.getTypeAndAttributes() & MCSectionMachO::SECTION_TYPE; - if (Type != MCSectionMachO::S_NON_LAZY_SYMBOL_POINTERS) + if (Section.getType() != MCSectionMachO::S_NON_LAZY_SYMBOL_POINTERS) continue; Asm.getOrCreateSymbolData(*it->Symbol); @@ -630,10 +627,8 @@ const MCSectionMachO &Section = static_cast(it->SectionData->getSection()); - unsigned Type = - Section.getTypeAndAttributes() & MCSectionMachO::SECTION_TYPE; - if (Type != MCSectionMachO::S_LAZY_SYMBOL_POINTERS && - Type != MCSectionMachO::S_SYMBOL_STUBS) + if (Section.getType() != MCSectionMachO::S_LAZY_SYMBOL_POINTERS && + Section.getType() != MCSectionMachO::S_SYMBOL_STUBS) continue; // Set the symbol type to undefined lazy, but only on construction. @@ -911,9 +906,7 @@ // special handling. const MCSectionMachO &Section = static_cast(it->SectionData->getSection()); - unsigned Type = - Section.getTypeAndAttributes() & MCSectionMachO::SECTION_TYPE; - if (Type == MCSectionMachO::S_NON_LAZY_SYMBOL_POINTERS) { + if (Section.getType() == MCSectionMachO::S_NON_LAZY_SYMBOL_POINTERS) { // If this symbol is defined and internal, mark it as such. if (it->Symbol->isDefined() && !Asm.getSymbolData(*it->Symbol).isExternal()) { From daniel at zuster.org Mon Mar 15 16:56:50 2010 From: daniel at zuster.org (Daniel Dunbar) Date: Mon, 15 Mar 2010 21:56:50 -0000 Subject: [llvm-commits] [llvm] r98583 - in /llvm/trunk: include/llvm/Target/TargetAsmBackend.h lib/MC/MCAssembler.cpp lib/Target/X86/X86AsmBackend.cpp test/MC/MachO/x86_32-symbols.s test/MC/MachO/x86_64-symbols.s Message-ID: <20100315215650.643A72A6C12D@llvm.org> Author: ddunbar Date: Mon Mar 15 16:56:50 2010 New Revision: 98583 URL: http://llvm.org/viewvc/llvm-project?rev=98583&view=rev Log: MC/Mach-O/x86_64: Temporary labels in cstring sections require symbols (and external relocations, but we don't have x86_64 relocations yet). Added: llvm/trunk/test/MC/MachO/x86_32-symbols.s llvm/trunk/test/MC/MachO/x86_64-symbols.s Modified: llvm/trunk/include/llvm/Target/TargetAsmBackend.h llvm/trunk/lib/MC/MCAssembler.cpp llvm/trunk/lib/Target/X86/X86AsmBackend.cpp Modified: llvm/trunk/include/llvm/Target/TargetAsmBackend.h URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/Target/TargetAsmBackend.h?rev=98583&r1=98582&r2=98583&view=diff ============================================================================== --- llvm/trunk/include/llvm/Target/TargetAsmBackend.h (original) +++ llvm/trunk/include/llvm/Target/TargetAsmBackend.h Mon Mar 15 16:56:50 2010 @@ -11,6 +11,7 @@ #define LLVM_TARGET_TARGETASMBACKEND_H namespace llvm { +class MCSection; class Target; /// TargetAsmBackend - Generic interface to target specific assembler backends. @@ -50,6 +51,12 @@ /// Note that the assembler currently does not reason about atoms, instead it /// assumes all temporary symbols reside in the "current atom". virtual bool hasScatteredSymbols() const { return false; } + + /// doesSectionRequireSymbols - Check whether the given section requires that + /// all symbols (even temporaries) have symbol table entries. + virtual bool doesSectionRequireSymbols(const MCSection &Section) const { + return false; + } }; } // End llvm namespace Modified: llvm/trunk/lib/MC/MCAssembler.cpp URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/MC/MCAssembler.cpp?rev=98583&r1=98582&r2=98583&view=diff ============================================================================== --- llvm/trunk/lib/MC/MCAssembler.cpp (original) +++ llvm/trunk/lib/MC/MCAssembler.cpp Mon Mar 15 16:56:50 2010 @@ -674,7 +674,10 @@ const MCSymbol &Symbol = it->getSymbol(); // Ignore assembler temporaries. - if (it->getSymbol().isTemporary()) + if (it->getSymbol().isTemporary() && + (!it->getFragment() || + !Asm.getBackend().doesSectionRequireSymbols( + it->getFragment()->getParent()->getSection()))) continue; if (!it->isExternal() && !Symbol.isUndefined()) @@ -710,7 +713,10 @@ const MCSymbol &Symbol = it->getSymbol(); // Ignore assembler temporaries. - if (it->getSymbol().isTemporary()) + if (it->getSymbol().isTemporary() && + (!it->getFragment() || + !Asm.getBackend().doesSectionRequireSymbols( + it->getFragment()->getParent()->getSection()))) continue; if (it->isExternal() || Symbol.isUndefined()) Modified: llvm/trunk/lib/Target/X86/X86AsmBackend.cpp URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Target/X86/X86AsmBackend.cpp?rev=98583&r1=98582&r2=98583&view=diff ============================================================================== --- llvm/trunk/lib/Target/X86/X86AsmBackend.cpp (original) +++ llvm/trunk/lib/Target/X86/X86AsmBackend.cpp Mon Mar 15 16:56:50 2010 @@ -9,6 +9,7 @@ #include "llvm/Target/TargetAsmBackend.h" #include "X86.h" +#include "llvm/MC/MCSectionMachO.h" #include "llvm/Target/TargetRegistry.h" #include "llvm/Target/TargetAsmBackend.h" using namespace llvm; @@ -31,13 +32,38 @@ virtual bool hasScatteredSymbols() const { return true; } }; +class DarwinX86_32AsmBackend : public DarwinX86AsmBackend { +public: + DarwinX86_32AsmBackend(const Target &T) + : DarwinX86AsmBackend(T) {} +}; + +class DarwinX86_64AsmBackend : public DarwinX86AsmBackend { +public: + DarwinX86_64AsmBackend(const Target &T) + : DarwinX86AsmBackend(T) {} + + virtual bool doesSectionRequireSymbols(const MCSection &Section) const { + // Temporary labels in the string literals sections require symbols. The + // issue is that the x86_64 relocation format does not allow symbol + + // offset, and so the linker does not have enough information to resolve the + // access to the appropriate atom unless an external relocation is used. For + // non-cstring sections, we expect the compiler to use a non-temporary label + // for anything that could have an addend pointing outside the symbol. + // + // See . + const MCSectionMachO &SMO = static_cast(Section); + return SMO.getType() == MCSectionMachO::S_CSTRING_LITERALS; + } +}; + } TargetAsmBackend *llvm::createX86_32AsmBackend(const Target &T, const std::string &TT) { switch (Triple(TT).getOS()) { case Triple::Darwin: - return new DarwinX86AsmBackend(T); + return new DarwinX86_32AsmBackend(T); default: return new X86AsmBackend(T); } @@ -47,7 +73,7 @@ const std::string &TT) { switch (Triple(TT).getOS()) { case Triple::Darwin: - return new DarwinX86AsmBackend(T); + return new DarwinX86_64AsmBackend(T); default: return new X86AsmBackend(T); } Added: llvm/trunk/test/MC/MachO/x86_32-symbols.s URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/MC/MachO/x86_32-symbols.s?rev=98583&view=auto ============================================================================== --- llvm/trunk/test/MC/MachO/x86_32-symbols.s (added) +++ llvm/trunk/test/MC/MachO/x86_32-symbols.s Mon Mar 15 16:56:50 2010 @@ -0,0 +1,1041 @@ +// RUN: llvm-mc -triple i386-apple-darwin9 %s -filetype=obj -o - | macho-dump | FileCheck %s + + .text +L0: +D0: + .section __TEXT,__text,regular,pure_instructions +L1: +D1: + .const +L2: +D2: + .static_const +L3: +D3: + .cstring +L4: +D4: + .literal4 +L5: +D5: + .literal8 +L6: +D6: + .literal16 +L7: +D7: + .constructor +L8: +D8: + .destructor +L9: +D9: + .symbol_stub +L10: +D10: + .picsymbol_stub +L11: +D11: + .data +L12: +D12: + .static_data +L13: +D13: + .non_lazy_symbol_pointer +L14: +D14: + .lazy_symbol_pointer +L15: +D15: + .dyld +L16: +D16: + .mod_init_func +L17: +D17: + .mod_term_func +L18: +D18: + .const_data +L19: +D19: + .objc_class +L20: +D20: + .objc_meta_class +L21: +D21: + .objc_cat_cls_meth +L22: +D22: + .objc_cat_inst_meth +L23: +D23: + .objc_protocol +L24: +D24: + .objc_string_object +L25: +D25: + .objc_cls_meth +L26: +D26: + .objc_inst_meth +L27: +D27: + .objc_cls_refs +L28: +D28: + .objc_message_refs +L29: +D29: + .objc_symbols +L30: +D30: + .objc_category +L31: +D31: + .objc_class_vars +L32: +D32: + .objc_instance_vars +L33: +D33: + .objc_module_info +L34: +D34: + .objc_class_names +L35: +D35: + .objc_meth_var_types +L36: +D36: + .objc_meth_var_names +L37: +D37: + .objc_selector_strs +L38: +D38: + .section __TEXT,__picsymbolstub4,symbol_stubs,none,16 +L39: +D39: + +// CHECK: ('cputype', 7) +// CHECK: ('cpusubtype', 3) +// CHECK: ('filetype', 1) +// CHECK: ('num_load_commands', 1) +// CHECK: ('load_commands_size', 2608) +// CHECK: ('flag', 0) +// CHECK: ('load_commands', [ +// CHECK: # Load Command 0 +// CHECK: (('command', 1) +// CHECK: ('size', 2504) +// CHECK: ('segment_name', '\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00') +// CHECK: ('vm_addr', 0) +// CHECK: ('vm_size', 0) +// CHECK: ('file_offset', 2636) +// CHECK: ('file_size', 0) +// CHECK: ('maxprot', 7) +// CHECK: ('initprot', 7) +// CHECK: ('num_sections', 36) +// CHECK: ('flags', 0) +// CHECK: ('sections', [ +// CHECK: # Section 0 +// CHECK: (('section_name', '__text\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00') +// CHECK: ('segment_name', '__TEXT\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00') +// CHECK: ('address', 0) +// CHECK: ('size', 0) +// CHECK: ('offset', 2636) +// CHECK: ('alignment', 0) +// CHECK: ('reloc_offset', 0) +// CHECK: ('num_reloc', 0) +// CHECK: ('flags', 0x80000000) +// CHECK: ('reserved1', 0) +// CHECK: ('reserved2', 0) +// CHECK: ), +// CHECK: ('_relocations', [ +// CHECK: ]) +// CHECK: # Section 1 +// CHECK: (('section_name', '__const\x00\x00\x00\x00\x00\x00\x00\x00\x00') +// CHECK: ('segment_name', '__TEXT\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00') +// CHECK: ('address', 0) +// CHECK: ('size', 0) +// CHECK: ('offset', 2636) +// CHECK: ('alignment', 0) +// CHECK: ('reloc_offset', 0) +// CHECK: ('num_reloc', 0) +// CHECK: ('flags', 0x0) +// CHECK: ('reserved1', 0) +// CHECK: ('reserved2', 0) +// CHECK: ), +// CHECK: ('_relocations', [ +// CHECK: ]) +// CHECK: # Section 2 +// CHECK: (('section_name', '__static_const\x00\x00') +// CHECK: ('segment_name', '__TEXT\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00') +// CHECK: ('address', 0) +// CHECK: ('size', 0) +// CHECK: ('offset', 2636) +// CHECK: ('alignment', 0) +// CHECK: ('reloc_offset', 0) +// CHECK: ('num_reloc', 0) +// CHECK: ('flags', 0x0) +// CHECK: ('reserved1', 0) +// CHECK: ('reserved2', 0) +// CHECK: ), +// CHECK: ('_relocations', [ +// CHECK: ]) +// CHECK: # Section 3 +// CHECK: (('section_name', '__cstring\x00\x00\x00\x00\x00\x00\x00') +// CHECK: ('segment_name', '__TEXT\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00') +// CHECK: ('address', 0) +// CHECK: ('size', 0) +// CHECK: ('offset', 2636) +// CHECK: ('alignment', 0) +// CHECK: ('reloc_offset', 0) +// CHECK: ('num_reloc', 0) +// CHECK: ('flags', 0x2) +// CHECK: ('reserved1', 0) +// CHECK: ('reserved2', 0) +// CHECK: ), +// CHECK: ('_relocations', [ +// CHECK: ]) +// CHECK: # Section 4 +// CHECK: (('section_name', '__literal4\x00\x00\x00\x00\x00\x00') +// CHECK: ('segment_name', '__TEXT\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00') +// CHECK: ('address', 0) +// CHECK: ('size', 0) +// CHECK: ('offset', 2636) +// CHECK: ('alignment', 2) +// CHECK: ('reloc_offset', 0) +// CHECK: ('num_reloc', 0) +// CHECK: ('flags', 0x3) +// CHECK: ('reserved1', 0) +// CHECK: ('reserved2', 0) +// CHECK: ), +// CHECK: ('_relocations', [ +// CHECK: ]) +// CHECK: # Section 5 +// CHECK: (('section_name', '__literal8\x00\x00\x00\x00\x00\x00') +// CHECK: ('segment_name', '__TEXT\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00') +// CHECK: ('address', 0) +// CHECK: ('size', 0) +// CHECK: ('offset', 2636) +// CHECK: ('alignment', 3) +// CHECK: ('reloc_offset', 0) +// CHECK: ('num_reloc', 0) +// CHECK: ('flags', 0x4) +// CHECK: ('reserved1', 0) +// CHECK: ('reserved2', 0) +// CHECK: ), +// CHECK: ('_relocations', [ +// CHECK: ]) +// CHECK: # Section 6 +// CHECK: (('section_name', '__literal16\x00\x00\x00\x00\x00') +// CHECK: ('segment_name', '__TEXT\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00') +// CHECK: ('address', 0) +// CHECK: ('size', 0) +// CHECK: ('offset', 2636) +// CHECK: ('alignment', 4) +// CHECK: ('reloc_offset', 0) +// CHECK: ('num_reloc', 0) +// CHECK: ('flags', 0xe) +// CHECK: ('reserved1', 0) +// CHECK: ('reserved2', 0) +// CHECK: ), +// CHECK: ('_relocations', [ +// CHECK: ]) +// CHECK: # Section 7 +// CHECK: (('section_name', '__constructor\x00\x00\x00') +// CHECK: ('segment_name', '__TEXT\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00') +// CHECK: ('address', 0) +// CHECK: ('size', 0) +// CHECK: ('offset', 2636) +// CHECK: ('alignment', 0) +// CHECK: ('reloc_offset', 0) +// CHECK: ('num_reloc', 0) +// CHECK: ('flags', 0x0) +// CHECK: ('reserved1', 0) +// CHECK: ('reserved2', 0) +// CHECK: ), +// CHECK: ('_relocations', [ +// CHECK: ]) +// CHECK: # Section 8 +// CHECK: (('section_name', '__destructor\x00\x00\x00\x00') +// CHECK: ('segment_name', '__TEXT\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00') +// CHECK: ('address', 0) +// CHECK: ('size', 0) +// CHECK: ('offset', 2636) +// CHECK: ('alignment', 0) +// CHECK: ('reloc_offset', 0) +// CHECK: ('num_reloc', 0) +// CHECK: ('flags', 0x0) +// CHECK: ('reserved1', 0) +// CHECK: ('reserved2', 0) +// CHECK: ), +// CHECK: ('_relocations', [ +// CHECK: ]) +// CHECK: # Section 9 +// CHECK: (('section_name', '__symbol_stub\x00\x00\x00') +// CHECK: ('segment_name', '__TEXT\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00') +// CHECK: ('address', 0) +// CHECK: ('size', 0) +// CHECK: ('offset', 2636) +// CHECK: ('alignment', 0) +// CHECK: ('reloc_offset', 0) +// CHECK: ('num_reloc', 0) +// CHECK: ('flags', 0x80000008) +// CHECK: ('reserved1', 0) +// CHECK: ('reserved2', 16) +// CHECK: ), +// CHECK: ('_relocations', [ +// CHECK: ]) +// CHECK: # Section 10 +// CHECK: (('section_name', '__picsymbol_stub') +// CHECK: ('segment_name', '__TEXT\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00') +// CHECK: ('address', 0) +// CHECK: ('size', 0) +// CHECK: ('offset', 2636) +// CHECK: ('alignment', 0) +// CHECK: ('reloc_offset', 0) +// CHECK: ('num_reloc', 0) +// CHECK: ('flags', 0x80000008) +// CHECK: ('reserved1', 0) +// CHECK: ('reserved2', 26) +// CHECK: ), +// CHECK: ('_relocations', [ +// CHECK: ]) +// CHECK: # Section 11 +// CHECK: (('section_name', '__data\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00') +// CHECK: ('segment_name', '__DATA\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00') +// CHECK: ('address', 0) +// CHECK: ('size', 0) +// CHECK: ('offset', 2636) +// CHECK: ('alignment', 0) +// CHECK: ('reloc_offset', 0) +// CHECK: ('num_reloc', 0) +// CHECK: ('flags', 0x0) +// CHECK: ('reserved1', 0) +// CHECK: ('reserved2', 0) +// CHECK: ), +// CHECK: ('_relocations', [ +// CHECK: ]) +// CHECK: # Section 12 +// CHECK: (('section_name', '__static_data\x00\x00\x00') +// CHECK: ('segment_name', '__DATA\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00') +// CHECK: ('address', 0) +// CHECK: ('size', 0) +// CHECK: ('offset', 2636) +// CHECK: ('alignment', 0) +// CHECK: ('reloc_offset', 0) +// CHECK: ('num_reloc', 0) +// CHECK: ('flags', 0x0) +// CHECK: ('reserved1', 0) +// CHECK: ('reserved2', 0) +// CHECK: ), +// CHECK: ('_relocations', [ +// CHECK: ]) +// CHECK: # Section 13 +// CHECK: (('section_name', '__nl_symbol_ptr\x00') +// CHECK: ('segment_name', '__DATA\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00') +// CHECK: ('address', 0) +// CHECK: ('size', 0) +// CHECK: ('offset', 2636) +// CHECK: ('alignment', 2) +// CHECK: ('reloc_offset', 0) +// CHECK: ('num_reloc', 0) +// CHECK: ('flags', 0x6) +// CHECK: ('reserved1', 0) +// CHECK: ('reserved2', 0) +// CHECK: ), +// CHECK: ('_relocations', [ +// CHECK: ]) +// CHECK: # Section 14 +// CHECK: (('section_name', '__la_symbol_ptr\x00') +// CHECK: ('segment_name', '__DATA\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00') +// CHECK: ('address', 0) +// CHECK: ('size', 0) +// CHECK: ('offset', 2636) +// CHECK: ('alignment', 2) +// CHECK: ('reloc_offset', 0) +// CHECK: ('num_reloc', 0) +// CHECK: ('flags', 0x7) +// CHECK: ('reserved1', 0) +// CHECK: ('reserved2', 0) +// CHECK: ), +// CHECK: ('_relocations', [ +// CHECK: ]) +// CHECK: # Section 15 +// CHECK: (('section_name', '__dyld\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00') +// CHECK: ('segment_name', '__DATA\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00') +// CHECK: ('address', 0) +// CHECK: ('size', 0) +// CHECK: ('offset', 2636) +// CHECK: ('alignment', 0) +// CHECK: ('reloc_offset', 0) +// CHECK: ('num_reloc', 0) +// CHECK: ('flags', 0x0) +// CHECK: ('reserved1', 0) +// CHECK: ('reserved2', 0) +// CHECK: ), +// CHECK: ('_relocations', [ +// CHECK: ]) +// CHECK: # Section 16 +// CHECK: (('section_name', '__mod_init_func\x00') +// CHECK: ('segment_name', '__DATA\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00') +// CHECK: ('address', 0) +// CHECK: ('size', 0) +// CHECK: ('offset', 2636) +// CHECK: ('alignment', 2) +// CHECK: ('reloc_offset', 0) +// CHECK: ('num_reloc', 0) +// CHECK: ('flags', 0x9) +// CHECK: ('reserved1', 0) +// CHECK: ('reserved2', 0) +// CHECK: ), +// CHECK: ('_relocations', [ +// CHECK: ]) +// CHECK: # Section 17 +// CHECK: (('section_name', '__mod_term_func\x00') +// CHECK: ('segment_name', '__DATA\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00') +// CHECK: ('address', 0) +// CHECK: ('size', 0) +// CHECK: ('offset', 2636) +// CHECK: ('alignment', 2) +// CHECK: ('reloc_offset', 0) +// CHECK: ('num_reloc', 0) +// CHECK: ('flags', 0xa) +// CHECK: ('reserved1', 0) +// CHECK: ('reserved2', 0) +// CHECK: ), +// CHECK: ('_relocations', [ +// CHECK: ]) +// CHECK: # Section 18 +// CHECK: (('section_name', '__const\x00\x00\x00\x00\x00\x00\x00\x00\x00') +// CHECK: ('segment_name', '__DATA\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00') +// CHECK: ('address', 0) +// CHECK: ('size', 0) +// CHECK: ('offset', 2636) +// CHECK: ('alignment', 0) +// CHECK: ('reloc_offset', 0) +// CHECK: ('num_reloc', 0) +// CHECK: ('flags', 0x0) +// CHECK: ('reserved1', 0) +// CHECK: ('reserved2', 0) +// CHECK: ), +// CHECK: ('_relocations', [ +// CHECK: ]) +// CHECK: # Section 19 +// CHECK: (('section_name', '__class\x00\x00\x00\x00\x00\x00\x00\x00\x00') +// CHECK: ('segment_name', '__OBJC\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00') +// CHECK: ('address', 0) +// CHECK: ('size', 0) +// CHECK: ('offset', 2636) +// CHECK: ('alignment', 0) +// CHECK: ('reloc_offset', 0) +// CHECK: ('num_reloc', 0) +// CHECK: ('flags', 0x10000000) +// CHECK: ('reserved1', 0) +// CHECK: ('reserved2', 0) +// CHECK: ), +// CHECK: ('_relocations', [ +// CHECK: ]) +// CHECK: # Section 20 +// CHECK: (('section_name', '__meta_class\x00\x00\x00\x00') +// CHECK: ('segment_name', '__OBJC\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00') +// CHECK: ('address', 0) +// CHECK: ('size', 0) +// CHECK: ('offset', 2636) +// CHECK: ('alignment', 0) +// CHECK: ('reloc_offset', 0) +// CHECK: ('num_reloc', 0) +// CHECK: ('flags', 0x10000000) +// CHECK: ('reserved1', 0) +// CHECK: ('reserved2', 0) +// CHECK: ), +// CHECK: ('_relocations', [ +// CHECK: ]) +// CHECK: # Section 21 +// CHECK: (('section_name', '__cat_cls_meth\x00\x00') +// CHECK: ('segment_name', '__OBJC\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00') +// CHECK: ('address', 0) +// CHECK: ('size', 0) +// CHECK: ('offset', 2636) +// CHECK: ('alignment', 0) +// CHECK: ('reloc_offset', 0) +// CHECK: ('num_reloc', 0) +// CHECK: ('flags', 0x10000000) +// CHECK: ('reserved1', 0) +// CHECK: ('reserved2', 0) +// CHECK: ), +// CHECK: ('_relocations', [ +// CHECK: ]) +// CHECK: # Section 22 +// CHECK: (('section_name', '__cat_inst_meth\x00') +// CHECK: ('segment_name', '__OBJC\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00') +// CHECK: ('address', 0) +// CHECK: ('size', 0) +// CHECK: ('offset', 2636) +// CHECK: ('alignment', 0) +// CHECK: ('reloc_offset', 0) +// CHECK: ('num_reloc', 0) +// CHECK: ('flags', 0x10000000) +// CHECK: ('reserved1', 0) +// CHECK: ('reserved2', 0) +// CHECK: ), +// CHECK: ('_relocations', [ +// CHECK: ]) +// CHECK: # Section 23 +// CHECK: (('section_name', '__protocol\x00\x00\x00\x00\x00\x00') +// CHECK: ('segment_name', '__OBJC\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00') +// CHECK: ('address', 0) +// CHECK: ('size', 0) +// CHECK: ('offset', 2636) +// CHECK: ('alignment', 0) +// CHECK: ('reloc_offset', 0) +// CHECK: ('num_reloc', 0) +// CHECK: ('flags', 0x10000000) +// CHECK: ('reserved1', 0) +// CHECK: ('reserved2', 0) +// CHECK: ), +// CHECK: ('_relocations', [ +// CHECK: ]) +// CHECK: # Section 24 +// CHECK: (('section_name', '__string_object\x00') +// CHECK: ('segment_name', '__OBJC\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00') +// CHECK: ('address', 0) +// CHECK: ('size', 0) +// CHECK: ('offset', 2636) +// CHECK: ('alignment', 0) +// CHECK: ('reloc_offset', 0) +// CHECK: ('num_reloc', 0) +// CHECK: ('flags', 0x10000000) +// CHECK: ('reserved1', 0) +// CHECK: ('reserved2', 0) +// CHECK: ), +// CHECK: ('_relocations', [ +// CHECK: ]) +// CHECK: # Section 25 +// CHECK: (('section_name', '__cls_meth\x00\x00\x00\x00\x00\x00') +// CHECK: ('segment_name', '__OBJC\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00') +// CHECK: ('address', 0) +// CHECK: ('size', 0) +// CHECK: ('offset', 2636) +// CHECK: ('alignment', 0) +// CHECK: ('reloc_offset', 0) +// CHECK: ('num_reloc', 0) +// CHECK: ('flags', 0x10000000) +// CHECK: ('reserved1', 0) +// CHECK: ('reserved2', 0) +// CHECK: ), +// CHECK: ('_relocations', [ +// CHECK: ]) +// CHECK: # Section 26 +// CHECK: (('section_name', '__inst_meth\x00\x00\x00\x00\x00') +// CHECK: ('segment_name', '__OBJC\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00') +// CHECK: ('address', 0) +// CHECK: ('size', 0) +// CHECK: ('offset', 2636) +// CHECK: ('alignment', 0) +// CHECK: ('reloc_offset', 0) +// CHECK: ('num_reloc', 0) +// CHECK: ('flags', 0x10000000) +// CHECK: ('reserved1', 0) +// CHECK: ('reserved2', 0) +// CHECK: ), +// CHECK: ('_relocations', [ +// CHECK: ]) +// CHECK: # Section 27 +// CHECK: (('section_name', '__cls_refs\x00\x00\x00\x00\x00\x00') +// CHECK: ('segment_name', '__OBJC\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00') +// CHECK: ('address', 0) +// CHECK: ('size', 0) +// CHECK: ('offset', 2636) +// CHECK: ('alignment', 2) +// CHECK: ('reloc_offset', 0) +// CHECK: ('num_reloc', 0) +// CHECK: ('flags', 0x10000005) +// CHECK: ('reserved1', 0) +// CHECK: ('reserved2', 0) +// CHECK: ), +// CHECK: ('_relocations', [ +// CHECK: ]) +// CHECK: # Section 28 +// CHECK: (('section_name', '__message_refs\x00\x00') +// CHECK: ('segment_name', '__OBJC\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00') +// CHECK: ('address', 0) +// CHECK: ('size', 0) +// CHECK: ('offset', 2636) +// CHECK: ('alignment', 2) +// CHECK: ('reloc_offset', 0) +// CHECK: ('num_reloc', 0) +// CHECK: ('flags', 0x10000005) +// CHECK: ('reserved1', 0) +// CHECK: ('reserved2', 0) +// CHECK: ), +// CHECK: ('_relocations', [ +// CHECK: ]) +// CHECK: # Section 29 +// CHECK: (('section_name', '__symbols\x00\x00\x00\x00\x00\x00\x00') +// CHECK: ('segment_name', '__OBJC\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00') +// CHECK: ('address', 0) +// CHECK: ('size', 0) +// CHECK: ('offset', 2636) +// CHECK: ('alignment', 0) +// CHECK: ('reloc_offset', 0) +// CHECK: ('num_reloc', 0) +// CHECK: ('flags', 0x10000000) +// CHECK: ('reserved1', 0) +// CHECK: ('reserved2', 0) +// CHECK: ), +// CHECK: ('_relocations', [ +// CHECK: ]) +// CHECK: # Section 30 +// CHECK: (('section_name', '__category\x00\x00\x00\x00\x00\x00') +// CHECK: ('segment_name', '__OBJC\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00') +// CHECK: ('address', 0) +// CHECK: ('size', 0) +// CHECK: ('offset', 2636) +// CHECK: ('alignment', 0) +// CHECK: ('reloc_offset', 0) +// CHECK: ('num_reloc', 0) +// CHECK: ('flags', 0x10000000) +// CHECK: ('reserved1', 0) +// CHECK: ('reserved2', 0) +// CHECK: ), +// CHECK: ('_relocations', [ +// CHECK: ]) +// CHECK: # Section 31 +// CHECK: (('section_name', '__class_vars\x00\x00\x00\x00') +// CHECK: ('segment_name', '__OBJC\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00') +// CHECK: ('address', 0) +// CHECK: ('size', 0) +// CHECK: ('offset', 2636) +// CHECK: ('alignment', 0) +// CHECK: ('reloc_offset', 0) +// CHECK: ('num_reloc', 0) +// CHECK: ('flags', 0x10000000) +// CHECK: ('reserved1', 0) +// CHECK: ('reserved2', 0) +// CHECK: ), +// CHECK: ('_relocations', [ +// CHECK: ]) +// CHECK: # Section 32 +// CHECK: (('section_name', '__instance_vars\x00') +// CHECK: ('segment_name', '__OBJC\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00') +// CHECK: ('address', 0) +// CHECK: ('size', 0) +// CHECK: ('offset', 2636) +// CHECK: ('alignment', 0) +// CHECK: ('reloc_offset', 0) +// CHECK: ('num_reloc', 0) +// CHECK: ('flags', 0x10000000) +// CHECK: ('reserved1', 0) +// CHECK: ('reserved2', 0) +// CHECK: ), +// CHECK: ('_relocations', [ +// CHECK: ]) +// CHECK: # Section 33 +// CHECK: (('section_name', '__module_info\x00\x00\x00') +// CHECK: ('segment_name', '__OBJC\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00') +// CHECK: ('address', 0) +// CHECK: ('size', 0) +// CHECK: ('offset', 2636) +// CHECK: ('alignment', 0) +// CHECK: ('reloc_offset', 0) +// CHECK: ('num_reloc', 0) +// CHECK: ('flags', 0x10000000) +// CHECK: ('reserved1', 0) +// CHECK: ('reserved2', 0) +// CHECK: ), +// CHECK: ('_relocations', [ +// CHECK: ]) +// CHECK: # Section 34 +// CHECK: (('section_name', '__selector_strs\x00') +// CHECK: ('segment_name', '__OBJC\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00') +// CHECK: ('address', 0) +// CHECK: ('size', 0) +// CHECK: ('offset', 2636) +// CHECK: ('alignment', 0) +// CHECK: ('reloc_offset', 0) +// CHECK: ('num_reloc', 0) +// CHECK: ('flags', 0x2) +// CHECK: ('reserved1', 0) +// CHECK: ('reserved2', 0) +// CHECK: ), +// CHECK: ('_relocations', [ +// CHECK: ]) +// CHECK: # Section 35 +// CHECK: (('section_name', '__picsymbolstub4') +// CHECK: ('segment_name', '__TEXT\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00') +// CHECK: ('address', 0) +// CHECK: ('size', 0) +// CHECK: ('offset', 2636) +// CHECK: ('alignment', 0) +// CHECK: ('reloc_offset', 0) +// CHECK: ('num_reloc', 0) +// CHECK: ('flags', 0x8) +// CHECK: ('reserved1', 0) +// CHECK: ('reserved2', 16) +// CHECK: ), +// CHECK: ('_relocations', [ +// CHECK: ]) +// CHECK: ]) +// CHECK: ), +// CHECK: # Load Command 1 +// CHECK: (('command', 2) +// CHECK: ('size', 24) +// CHECK: ('symoff', 2636) +// CHECK: ('nsyms', 40) +// CHECK: ('stroff', 3116) +// CHECK: ('strsize', 152) +// CHECK: ('_string_data', '\x00D0\x00D1\x00D2\x00D3\x00D4\x00D5\x00D6\x00D7\x00D8\x00D9\x00D10\x00D11\x00D12\x00D13\x00D14\x00D15\x00D16\x00D17\x00D18\x00D19\x00D20\x00D21\x00D22\x00D23\x00D24\x00D25\x00D26\x00D27\x00D28\x00D29\x00D30\x00D31\x00D32\x00D33\x00D34\x00D35\x00D36\x00D37\x00D38\x00D39\x00\x00') +// CHECK: ('_symbols', [ +// CHECK: # Symbol 0 +// CHECK: (('n_strx', 1) +// CHECK: ('n_type', 0xe) +// CHECK: ('n_sect', 1) +// CHECK: ('n_desc', 0) +// CHECK: ('n_value', 0) +// CHECK: ('_string', 'D0') +// CHECK: ), +// CHECK: # Symbol 1 +// CHECK: (('n_strx', 4) +// CHECK: ('n_type', 0xe) +// CHECK: ('n_sect', 1) +// CHECK: ('n_desc', 0) +// CHECK: ('n_value', 0) +// CHECK: ('_string', 'D1') +// CHECK: ), +// CHECK: # Symbol 2 +// CHECK: (('n_strx', 7) +// CHECK: ('n_type', 0xe) +// CHECK: ('n_sect', 2) +// CHECK: ('n_desc', 0) +// CHECK: ('n_value', 0) +// CHECK: ('_string', 'D2') +// CHECK: ), +// CHECK: # Symbol 3 +// CHECK: (('n_strx', 10) +// CHECK: ('n_type', 0xe) +// CHECK: ('n_sect', 3) +// CHECK: ('n_desc', 0) +// CHECK: ('n_value', 0) +// CHECK: ('_string', 'D3') +// CHECK: ), +// CHECK: # Symbol 4 +// CHECK: (('n_strx', 13) +// CHECK: ('n_type', 0xe) +// CHECK: ('n_sect', 4) +// CHECK: ('n_desc', 0) +// CHECK: ('n_value', 0) +// CHECK: ('_string', 'D4') +// CHECK: ), +// CHECK: # Symbol 5 +// CHECK: (('n_strx', 16) +// CHECK: ('n_type', 0xe) +// CHECK: ('n_sect', 5) +// CHECK: ('n_desc', 0) +// CHECK: ('n_value', 0) +// CHECK: ('_string', 'D5') +// CHECK: ), +// CHECK: # Symbol 6 +// CHECK: (('n_strx', 19) +// CHECK: ('n_type', 0xe) +// CHECK: ('n_sect', 6) +// CHECK: ('n_desc', 0) +// CHECK: ('n_value', 0) +// CHECK: ('_string', 'D6') +// CHECK: ), +// CHECK: # Symbol 7 +// CHECK: (('n_strx', 22) +// CHECK: ('n_type', 0xe) +// CHECK: ('n_sect', 7) +// CHECK: ('n_desc', 0) +// CHECK: ('n_value', 0) +// CHECK: ('_string', 'D7') +// CHECK: ), +// CHECK: # Symbol 8 +// CHECK: (('n_strx', 25) +// CHECK: ('n_type', 0xe) +// CHECK: ('n_sect', 8) +// CHECK: ('n_desc', 0) +// CHECK: ('n_value', 0) +// CHECK: ('_string', 'D8') +// CHECK: ), +// CHECK: # Symbol 9 +// CHECK: (('n_strx', 28) +// CHECK: ('n_type', 0xe) +// CHECK: ('n_sect', 9) +// CHECK: ('n_desc', 0) +// CHECK: ('n_value', 0) +// CHECK: ('_string', 'D9') +// CHECK: ), +// CHECK: # Symbol 10 +// CHECK: (('n_strx', 31) +// CHECK: ('n_type', 0xe) +// CHECK: ('n_sect', 10) +// CHECK: ('n_desc', 0) +// CHECK: ('n_value', 0) +// CHECK: ('_string', 'D10') +// CHECK: ), +// CHECK: # Symbol 11 +// CHECK: (('n_strx', 35) +// CHECK: ('n_type', 0xe) +// CHECK: ('n_sect', 11) +// CHECK: ('n_desc', 0) +// CHECK: ('n_value', 0) +// CHECK: ('_string', 'D11') +// CHECK: ), +// CHECK: # Symbol 12 +// CHECK: (('n_strx', 39) +// CHECK: ('n_type', 0xe) +// CHECK: ('n_sect', 12) +// CHECK: ('n_desc', 0) +// CHECK: ('n_value', 0) +// CHECK: ('_string', 'D12') +// CHECK: ), +// CHECK: # Symbol 13 +// CHECK: (('n_strx', 43) +// CHECK: ('n_type', 0xe) +// CHECK: ('n_sect', 13) +// CHECK: ('n_desc', 0) +// CHECK: ('n_value', 0) +// CHECK: ('_string', 'D13') +// CHECK: ), +// CHECK: # Symbol 14 +// CHECK: (('n_strx', 47) +// CHECK: ('n_type', 0xe) +// CHECK: ('n_sect', 14) +// CHECK: ('n_desc', 0) +// CHECK: ('n_value', 0) +// CHECK: ('_string', 'D14') +// CHECK: ), +// CHECK: # Symbol 15 +// CHECK: (('n_strx', 51) +// CHECK: ('n_type', 0xe) +// CHECK: ('n_sect', 15) +// CHECK: ('n_desc', 0) +// CHECK: ('n_value', 0) +// CHECK: ('_string', 'D15') +// CHECK: ), +// CHECK: # Symbol 16 +// CHECK: (('n_strx', 55) +// CHECK: ('n_type', 0xe) +// CHECK: ('n_sect', 16) +// CHECK: ('n_desc', 0) +// CHECK: ('n_value', 0) +// CHECK: ('_string', 'D16') +// CHECK: ), +// CHECK: # Symbol 17 +// CHECK: (('n_strx', 59) +// CHECK: ('n_type', 0xe) +// CHECK: ('n_sect', 17) +// CHECK: ('n_desc', 0) +// CHECK: ('n_value', 0) +// CHECK: ('_string', 'D17') +// CHECK: ), +// CHECK: # Symbol 18 +// CHECK: (('n_strx', 63) +// CHECK: ('n_type', 0xe) +// CHECK: ('n_sect', 18) +// CHECK: ('n_desc', 0) +// CHECK: ('n_value', 0) +// CHECK: ('_string', 'D18') +// CHECK: ), +// CHECK: # Symbol 19 +// CHECK: (('n_strx', 67) +// CHECK: ('n_type', 0xe) +// CHECK: ('n_sect', 19) +// CHECK: ('n_desc', 0) +// CHECK: ('n_value', 0) +// CHECK: ('_string', 'D19') +// CHECK: ), +// CHECK: # Symbol 20 +// CHECK: (('n_strx', 71) +// CHECK: ('n_type', 0xe) +// CHECK: ('n_sect', 20) +// CHECK: ('n_desc', 0) +// CHECK: ('n_value', 0) +// CHECK: ('_string', 'D20') +// CHECK: ), +// CHECK: # Symbol 21 +// CHECK: (('n_strx', 75) +// CHECK: ('n_type', 0xe) +// CHECK: ('n_sect', 21) +// CHECK: ('n_desc', 0) +// CHECK: ('n_value', 0) +// CHECK: ('_string', 'D21') +// CHECK: ), +// CHECK: # Symbol 22 +// CHECK: (('n_strx', 79) +// CHECK: ('n_type', 0xe) +// CHECK: ('n_sect', 22) +// CHECK: ('n_desc', 0) +// CHECK: ('n_value', 0) +// CHECK: ('_string', 'D22') +// CHECK: ), +// CHECK: # Symbol 23 +// CHECK: (('n_strx', 83) +// CHECK: ('n_type', 0xe) +// CHECK: ('n_sect', 23) +// CHECK: ('n_desc', 0) +// CHECK: ('n_value', 0) +// CHECK: ('_string', 'D23') +// CHECK: ), +// CHECK: # Symbol 24 +// CHECK: (('n_strx', 87) +// CHECK: ('n_type', 0xe) +// CHECK: ('n_sect', 24) +// CHECK: ('n_desc', 0) +// CHECK: ('n_value', 0) +// CHECK: ('_string', 'D24') +// CHECK: ), +// CHECK: # Symbol 25 +// CHECK: (('n_strx', 91) +// CHECK: ('n_type', 0xe) +// CHECK: ('n_sect', 25) +// CHECK: ('n_desc', 0) +// CHECK: ('n_value', 0) +// CHECK: ('_string', 'D25') +// CHECK: ), +// CHECK: # Symbol 26 +// CHECK: (('n_strx', 95) +// CHECK: ('n_type', 0xe) +// CHECK: ('n_sect', 26) +// CHECK: ('n_desc', 0) +// CHECK: ('n_value', 0) +// CHECK: ('_string', 'D26') +// CHECK: ), +// CHECK: # Symbol 27 +// CHECK: (('n_strx', 99) +// CHECK: ('n_type', 0xe) +// CHECK: ('n_sect', 27) +// CHECK: ('n_desc', 0) +// CHECK: ('n_value', 0) +// CHECK: ('_string', 'D27') +// CHECK: ), +// CHECK: # Symbol 28 +// CHECK: (('n_strx', 103) +// CHECK: ('n_type', 0xe) +// CHECK: ('n_sect', 28) +// CHECK: ('n_desc', 0) +// CHECK: ('n_value', 0) +// CHECK: ('_string', 'D28') +// CHECK: ), +// CHECK: # Symbol 29 +// CHECK: (('n_strx', 107) +// CHECK: ('n_type', 0xe) +// CHECK: ('n_sect', 29) +// CHECK: ('n_desc', 0) +// CHECK: ('n_value', 0) +// CHECK: ('_string', 'D29') +// CHECK: ), +// CHECK: # Symbol 30 +// CHECK: (('n_strx', 111) +// CHECK: ('n_type', 0xe) +// CHECK: ('n_sect', 30) +// CHECK: ('n_desc', 0) +// CHECK: ('n_value', 0) +// CHECK: ('_string', 'D30') +// CHECK: ), +// CHECK: # Symbol 31 +// CHECK: (('n_strx', 115) +// CHECK: ('n_type', 0xe) +// CHECK: ('n_sect', 31) +// CHECK: ('n_desc', 0) +// CHECK: ('n_value', 0) +// CHECK: ('_string', 'D31') +// CHECK: ), +// CHECK: # Symbol 32 +// CHECK: (('n_strx', 119) +// CHECK: ('n_type', 0xe) +// CHECK: ('n_sect', 32) +// CHECK: ('n_desc', 0) +// CHECK: ('n_value', 0) +// CHECK: ('_string', 'D32') +// CHECK: ), +// CHECK: # Symbol 33 +// CHECK: (('n_strx', 123) +// CHECK: ('n_type', 0xe) +// CHECK: ('n_sect', 33) +// CHECK: ('n_desc', 0) +// CHECK: ('n_value', 0) +// CHECK: ('_string', 'D33') +// CHECK: ), +// CHECK: # Symbol 34 +// CHECK: (('n_strx', 127) +// CHECK: ('n_type', 0xe) +// CHECK: ('n_sect', 34) +// CHECK: ('n_desc', 0) +// CHECK: ('n_value', 0) +// CHECK: ('_string', 'D34') +// CHECK: ), +// CHECK: # Symbol 35 +// CHECK: (('n_strx', 131) +// CHECK: ('n_type', 0xe) +// CHECK: ('n_sect', 4) +// CHECK: ('n_desc', 0) +// CHECK: ('n_value', 0) +// CHECK: ('_string', 'D35') +// CHECK: ), +// CHECK: # Symbol 36 +// CHECK: (('n_strx', 135) +// CHECK: ('n_type', 0xe) +// CHECK: ('n_sect', 4) +// CHECK: ('n_desc', 0) +// CHECK: ('n_value', 0) +// CHECK: ('_string', 'D36') +// CHECK: ), +// CHECK: # Symbol 37 +// CHECK: (('n_strx', 139) +// CHECK: ('n_type', 0xe) +// CHECK: ('n_sect', 4) +// CHECK: ('n_desc', 0) +// CHECK: ('n_value', 0) +// CHECK: ('_string', 'D37') +// CHECK: ), +// CHECK: # Symbol 38 +// CHECK: (('n_strx', 143) +// CHECK: ('n_type', 0xe) +// CHECK: ('n_sect', 35) +// CHECK: ('n_desc', 0) +// CHECK: ('n_value', 0) +// CHECK: ('_string', 'D38') +// CHECK: ), +// CHECK: # Symbol 39 +// CHECK: (('n_strx', 147) +// CHECK: ('n_type', 0xe) +// CHECK: ('n_sect', 36) +// CHECK: ('n_desc', 0) +// CHECK: ('n_value', 0) +// CHECK: ('_string', 'D39') +// CHECK: ), +// CHECK: ]) +// CHECK: ), +// CHECK: # Load Command 2 +// CHECK: (('command', 11) +// CHECK: ('size', 80) +// CHECK: ('ilocalsym', 0) +// CHECK: ('nlocalsym', 40) +// CHECK: ('iextdefsym', 40) +// CHECK: ('nextdefsym', 0) +// CHECK: ('iundefsym', 40) +// CHECK: ('nundefsym', 0) +// CHECK: ('tocoff', 0) +// CHECK: ('ntoc', 0) +// CHECK: ('modtaboff', 0) +// CHECK: ('nmodtab', 0) +// CHECK: ('extrefsymoff', 0) +// CHECK: ('nextrefsyms', 0) +// CHECK: ('indirectsymoff', 0) +// CHECK: ('nindirectsyms', 0) +// CHECK: ('extreloff', 0) +// CHECK: ('nextrel', 0) +// CHECK: ('locreloff', 0) +// CHECK: ('nlocrel', 0) +// CHECK: ('_indirect_symbols', [ +// CHECK: ]) +// CHECK: ), +// CHECK: ]) Added: llvm/trunk/test/MC/MachO/x86_64-symbols.s URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/MC/MachO/x86_64-symbols.s?rev=98583&view=auto ============================================================================== --- llvm/trunk/test/MC/MachO/x86_64-symbols.s (added) +++ llvm/trunk/test/MC/MachO/x86_64-symbols.s Mon Mar 15 16:56:50 2010 @@ -0,0 +1,998 @@ +// RUN: llvm-mc -triple x86_64-apple-darwin10 %s -filetype=obj -o - | macho-dump | FileCheck %s + + .text +L0: +D0: + .section __TEXT,__text,regular,pure_instructions +L1: +D1: + .const +L2: +D2: + .static_const +L3: +D3: + .cstring +L4: +D4: + .literal4 +L5: +D5: + .literal8 +L6: +D6: + .literal16 +L7: +D7: + .constructor +L8: +D8: + .destructor +L9: +D9: +// .symbol_stub +//L10: +//D10: +// .picsymbol_stub +//L11: +//D11: + .data +L12: +D12: + .static_data +L13: +D13: +// .non_lazy_symbol_pointer +//L14: +//D14: +// .lazy_symbol_pointer +//L15: +//D15: + .dyld +L16: +D16: + .mod_init_func +L17: +D17: + .mod_term_func +L18: +D18: + .const_data +L19: +D19: + .objc_class +L20: +D20: + .objc_meta_class +L21: +D21: + .objc_cat_cls_meth +L22: +D22: + .objc_cat_inst_meth +L23: +D23: + .objc_protocol +L24: +D24: + .objc_string_object +L25: +D25: + .objc_cls_meth +L26: +D26: + .objc_inst_meth +L27: +D27: + .objc_cls_refs +L28: +D28: + .objc_message_refs +L29: +D29: + .objc_symbols +L30: +D30: + .objc_category +L31: +D31: + .objc_class_vars +L32: +D32: + .objc_instance_vars +L33: +D33: + .objc_module_info +L34: +D34: + .objc_class_names +L35: +D35: + .objc_meth_var_types +L36: +D36: + .objc_meth_var_names +L37: +D37: + .objc_selector_strs +L38: +D38: +// .section __TEXT,__picsymbolstub4,symbol_stubs,none,16 +//L39: +//D39: + +// CHECK: ('cputype', 16777223) +// CHECK: ('cpusubtype', 3) +// CHECK: ('filetype', 1) +// CHECK: ('num_load_commands', 1) +// CHECK: ('load_commands_size', 2656) +// CHECK: ('flag', 0) +// CHECK: ('reserved', 0) +// CHECK: ('load_commands', [ +// CHECK: # Load Command 0 +// CHECK: (('command', 25) +// CHECK: ('size', 2552) +// CHECK: ('segment_name', '\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00') +// CHECK: ('vm_addr', 0) +// CHECK: ('vm_size', 0) +// CHECK: ('file_offset', 2688) +// CHECK: ('file_size', 0) +// CHECK: ('maxprot', 7) +// CHECK: ('initprot', 7) +// CHECK: ('num_sections', 31) +// CHECK: ('flags', 0) +// CHECK: ('sections', [ +// CHECK: # Section 0 +// CHECK: (('section_name', '__text\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00') +// CHECK: ('segment_name', '__TEXT\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00') +// CHECK: ('address', 0) +// CHECK: ('size', 0) +// CHECK: ('offset', 2688) +// CHECK: ('alignment', 0) +// CHECK: ('reloc_offset', 0) +// CHECK: ('num_reloc', 0) +// CHECK: ('flags', 0x80000000) +// CHECK: ('reserved1', 0) +// CHECK: ('reserved2', 0) +// CHECK: ('reserved3', 0) +// CHECK: ), +// CHECK: ('_relocations', [ +// CHECK: ]) +// CHECK: # Section 1 +// CHECK: (('section_name', '__const\x00\x00\x00\x00\x00\x00\x00\x00\x00') +// CHECK: ('segment_name', '__TEXT\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00') +// CHECK: ('address', 0) +// CHECK: ('size', 0) +// CHECK: ('offset', 2688) +// CHECK: ('alignment', 0) +// CHECK: ('reloc_offset', 0) +// CHECK: ('num_reloc', 0) +// CHECK: ('flags', 0x0) +// CHECK: ('reserved1', 0) +// CHECK: ('reserved2', 0) +// CHECK: ('reserved3', 0) +// CHECK: ), +// CHECK: ('_relocations', [ +// CHECK: ]) +// CHECK: # Section 2 +// CHECK: (('section_name', '__static_const\x00\x00') +// CHECK: ('segment_name', '__TEXT\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00') +// CHECK: ('address', 0) +// CHECK: ('size', 0) +// CHECK: ('offset', 2688) +// CHECK: ('alignment', 0) +// CHECK: ('reloc_offset', 0) +// CHECK: ('num_reloc', 0) +// CHECK: ('flags', 0x0) +// CHECK: ('reserved1', 0) +// CHECK: ('reserved2', 0) +// CHECK: ('reserved3', 0) +// CHECK: ), +// CHECK: ('_relocations', [ +// CHECK: ]) +// CHECK: # Section 3 +// CHECK: (('section_name', '__cstring\x00\x00\x00\x00\x00\x00\x00') +// CHECK: ('segment_name', '__TEXT\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00') +// CHECK: ('address', 0) +// CHECK: ('size', 0) +// CHECK: ('offset', 2688) +// CHECK: ('alignment', 0) +// CHECK: ('reloc_offset', 0) +// CHECK: ('num_reloc', 0) +// CHECK: ('flags', 0x2) +// CHECK: ('reserved1', 0) +// CHECK: ('reserved2', 0) +// CHECK: ('reserved3', 0) +// CHECK: ), +// CHECK: ('_relocations', [ +// CHECK: ]) +// CHECK: # Section 4 +// CHECK: (('section_name', '__literal4\x00\x00\x00\x00\x00\x00') +// CHECK: ('segment_name', '__TEXT\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00') +// CHECK: ('address', 0) +// CHECK: ('size', 0) +// CHECK: ('offset', 2688) +// CHECK: ('alignment', 2) +// CHECK: ('reloc_offset', 0) +// CHECK: ('num_reloc', 0) +// CHECK: ('flags', 0x3) +// CHECK: ('reserved1', 0) +// CHECK: ('reserved2', 0) +// CHECK: ('reserved3', 0) +// CHECK: ), +// CHECK: ('_relocations', [ +// CHECK: ]) +// CHECK: # Section 5 +// CHECK: (('section_name', '__literal8\x00\x00\x00\x00\x00\x00') +// CHECK: ('segment_name', '__TEXT\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00') +// CHECK: ('address', 0) +// CHECK: ('size', 0) +// CHECK: ('offset', 2688) +// CHECK: ('alignment', 3) +// CHECK: ('reloc_offset', 0) +// CHECK: ('num_reloc', 0) +// CHECK: ('flags', 0x4) +// CHECK: ('reserved1', 0) +// CHECK: ('reserved2', 0) +// CHECK: ('reserved3', 0) +// CHECK: ), +// CHECK: ('_relocations', [ +// CHECK: ]) +// CHECK: # Section 6 +// CHECK: (('section_name', '__literal16\x00\x00\x00\x00\x00') +// CHECK: ('segment_name', '__TEXT\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00') +// CHECK: ('address', 0) +// CHECK: ('size', 0) +// CHECK: ('offset', 2688) +// CHECK: ('alignment', 4) +// CHECK: ('reloc_offset', 0) +// CHECK: ('num_reloc', 0) +// CHECK: ('flags', 0xe) +// CHECK: ('reserved1', 0) +// CHECK: ('reserved2', 0) +// CHECK: ('reserved3', 0) +// CHECK: ), +// CHECK: ('_relocations', [ +// CHECK: ]) +// CHECK: # Section 7 +// CHECK: (('section_name', '__constructor\x00\x00\x00') +// CHECK: ('segment_name', '__TEXT\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00') +// CHECK: ('address', 0) +// CHECK: ('size', 0) +// CHECK: ('offset', 2688) +// CHECK: ('alignment', 0) +// CHECK: ('reloc_offset', 0) +// CHECK: ('num_reloc', 0) +// CHECK: ('flags', 0x0) +// CHECK: ('reserved1', 0) +// CHECK: ('reserved2', 0) +// CHECK: ('reserved3', 0) +// CHECK: ), +// CHECK: ('_relocations', [ +// CHECK: ]) +// CHECK: # Section 8 +// CHECK: (('section_name', '__destructor\x00\x00\x00\x00') +// CHECK: ('segment_name', '__TEXT\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00') +// CHECK: ('address', 0) +// CHECK: ('size', 0) +// CHECK: ('offset', 2688) +// CHECK: ('alignment', 0) +// CHECK: ('reloc_offset', 0) +// CHECK: ('num_reloc', 0) +// CHECK: ('flags', 0x0) +// CHECK: ('reserved1', 0) +// CHECK: ('reserved2', 0) +// CHECK: ('reserved3', 0) +// CHECK: ), +// CHECK: ('_relocations', [ +// CHECK: ]) +// CHECK: # Section 9 +// CHECK: (('section_name', '__data\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00') +// CHECK: ('segment_name', '__DATA\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00') +// CHECK: ('address', 0) +// CHECK: ('size', 0) +// CHECK: ('offset', 2688) +// CHECK: ('alignment', 0) +// CHECK: ('reloc_offset', 0) +// CHECK: ('num_reloc', 0) +// CHECK: ('flags', 0x0) +// CHECK: ('reserved1', 0) +// CHECK: ('reserved2', 0) +// CHECK: ('reserved3', 0) +// CHECK: ), +// CHECK: ('_relocations', [ +// CHECK: ]) +// CHECK: # Section 10 +// CHECK: (('section_name', '__static_data\x00\x00\x00') +// CHECK: ('segment_name', '__DATA\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00') +// CHECK: ('address', 0) +// CHECK: ('size', 0) +// CHECK: ('offset', 2688) +// CHECK: ('alignment', 0) +// CHECK: ('reloc_offset', 0) +// CHECK: ('num_reloc', 0) +// CHECK: ('flags', 0x0) +// CHECK: ('reserved1', 0) +// CHECK: ('reserved2', 0) +// CHECK: ('reserved3', 0) +// CHECK: ), +// CHECK: ('_relocations', [ +// CHECK: ]) +// CHECK: # Section 11 +// CHECK: (('section_name', '__dyld\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00') +// CHECK: ('segment_name', '__DATA\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00') +// CHECK: ('address', 0) +// CHECK: ('size', 0) +// CHECK: ('offset', 2688) +// CHECK: ('alignment', 0) +// CHECK: ('reloc_offset', 0) +// CHECK: ('num_reloc', 0) +// CHECK: ('flags', 0x0) +// CHECK: ('reserved1', 0) +// CHECK: ('reserved2', 0) +// CHECK: ('reserved3', 0) +// CHECK: ), +// CHECK: ('_relocations', [ +// CHECK: ]) +// CHECK: # Section 12 +// CHECK: (('section_name', '__mod_init_func\x00') +// CHECK: ('segment_name', '__DATA\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00') +// CHECK: ('address', 0) +// CHECK: ('size', 0) +// CHECK: ('offset', 2688) +// CHECK: ('alignment', 2) +// CHECK: ('reloc_offset', 0) +// CHECK: ('num_reloc', 0) +// CHECK: ('flags', 0x9) +// CHECK: ('reserved1', 0) +// CHECK: ('reserved2', 0) +// CHECK: ('reserved3', 0) +// CHECK: ), +// CHECK: ('_relocations', [ +// CHECK: ]) +// CHECK: # Section 13 +// CHECK: (('section_name', '__mod_term_func\x00') +// CHECK: ('segment_name', '__DATA\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00') +// CHECK: ('address', 0) +// CHECK: ('size', 0) +// CHECK: ('offset', 2688) +// CHECK: ('alignment', 2) +// CHECK: ('reloc_offset', 0) +// CHECK: ('num_reloc', 0) +// CHECK: ('flags', 0xa) +// CHECK: ('reserved1', 0) +// CHECK: ('reserved2', 0) +// CHECK: ('reserved3', 0) +// CHECK: ), +// CHECK: ('_relocations', [ +// CHECK: ]) +// CHECK: # Section 14 +// CHECK: (('section_name', '__const\x00\x00\x00\x00\x00\x00\x00\x00\x00') +// CHECK: ('segment_name', '__DATA\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00') +// CHECK: ('address', 0) +// CHECK: ('size', 0) +// CHECK: ('offset', 2688) +// CHECK: ('alignment', 0) +// CHECK: ('reloc_offset', 0) +// CHECK: ('num_reloc', 0) +// CHECK: ('flags', 0x0) +// CHECK: ('reserved1', 0) +// CHECK: ('reserved2', 0) +// CHECK: ('reserved3', 0) +// CHECK: ), +// CHECK: ('_relocations', [ +// CHECK: ]) +// CHECK: # Section 15 +// CHECK: (('section_name', '__class\x00\x00\x00\x00\x00\x00\x00\x00\x00') +// CHECK: ('segment_name', '__OBJC\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00') +// CHECK: ('address', 0) +// CHECK: ('size', 0) +// CHECK: ('offset', 2688) +// CHECK: ('alignment', 0) +// CHECK: ('reloc_offset', 0) +// CHECK: ('num_reloc', 0) +// CHECK: ('flags', 0x10000000) +// CHECK: ('reserved1', 0) +// CHECK: ('reserved2', 0) +// CHECK: ('reserved3', 0) +// CHECK: ), +// CHECK: ('_relocations', [ +// CHECK: ]) +// CHECK: # Section 16 +// CHECK: (('section_name', '__meta_class\x00\x00\x00\x00') +// CHECK: ('segment_name', '__OBJC\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00') +// CHECK: ('address', 0) +// CHECK: ('size', 0) +// CHECK: ('offset', 2688) +// CHECK: ('alignment', 0) +// CHECK: ('reloc_offset', 0) +// CHECK: ('num_reloc', 0) +// CHECK: ('flags', 0x10000000) +// CHECK: ('reserved1', 0) +// CHECK: ('reserved2', 0) +// CHECK: ('reserved3', 0) +// CHECK: ), +// CHECK: ('_relocations', [ +// CHECK: ]) +// CHECK: # Section 17 +// CHECK: (('section_name', '__cat_cls_meth\x00\x00') +// CHECK: ('segment_name', '__OBJC\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00') +// CHECK: ('address', 0) +// CHECK: ('size', 0) +// CHECK: ('offset', 2688) +// CHECK: ('alignment', 0) +// CHECK: ('reloc_offset', 0) +// CHECK: ('num_reloc', 0) +// CHECK: ('flags', 0x10000000) +// CHECK: ('reserved1', 0) +// CHECK: ('reserved2', 0) +// CHECK: ('reserved3', 0) +// CHECK: ), +// CHECK: ('_relocations', [ +// CHECK: ]) +// CHECK: # Section 18 +// CHECK: (('section_name', '__cat_inst_meth\x00') +// CHECK: ('segment_name', '__OBJC\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00') +// CHECK: ('address', 0) +// CHECK: ('size', 0) +// CHECK: ('offset', 2688) +// CHECK: ('alignment', 0) +// CHECK: ('reloc_offset', 0) +// CHECK: ('num_reloc', 0) +// CHECK: ('flags', 0x10000000) +// CHECK: ('reserved1', 0) +// CHECK: ('reserved2', 0) +// CHECK: ('reserved3', 0) +// CHECK: ), +// CHECK: ('_relocations', [ +// CHECK: ]) +// CHECK: # Section 19 +// CHECK: (('section_name', '__protocol\x00\x00\x00\x00\x00\x00') +// CHECK: ('segment_name', '__OBJC\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00') +// CHECK: ('address', 0) +// CHECK: ('size', 0) +// CHECK: ('offset', 2688) +// CHECK: ('alignment', 0) +// CHECK: ('reloc_offset', 0) +// CHECK: ('num_reloc', 0) +// CHECK: ('flags', 0x10000000) +// CHECK: ('reserved1', 0) +// CHECK: ('reserved2', 0) +// CHECK: ('reserved3', 0) +// CHECK: ), +// CHECK: ('_relocations', [ +// CHECK: ]) +// CHECK: # Section 20 +// CHECK: (('section_name', '__string_object\x00') +// CHECK: ('segment_name', '__OBJC\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00') +// CHECK: ('address', 0) +// CHECK: ('size', 0) +// CHECK: ('offset', 2688) +// CHECK: ('alignment', 0) +// CHECK: ('reloc_offset', 0) +// CHECK: ('num_reloc', 0) +// CHECK: ('flags', 0x10000000) +// CHECK: ('reserved1', 0) +// CHECK: ('reserved2', 0) +// CHECK: ('reserved3', 0) +// CHECK: ), +// CHECK: ('_relocations', [ +// CHECK: ]) +// CHECK: # Section 21 +// CHECK: (('section_name', '__cls_meth\x00\x00\x00\x00\x00\x00') +// CHECK: ('segment_name', '__OBJC\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00') +// CHECK: ('address', 0) +// CHECK: ('size', 0) +// CHECK: ('offset', 2688) +// CHECK: ('alignment', 0) +// CHECK: ('reloc_offset', 0) +// CHECK: ('num_reloc', 0) +// CHECK: ('flags', 0x10000000) +// CHECK: ('reserved1', 0) +// CHECK: ('reserved2', 0) +// CHECK: ('reserved3', 0) +// CHECK: ), +// CHECK: ('_relocations', [ +// CHECK: ]) +// CHECK: # Section 22 +// CHECK: (('section_name', '__inst_meth\x00\x00\x00\x00\x00') +// CHECK: ('segment_name', '__OBJC\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00') +// CHECK: ('address', 0) +// CHECK: ('size', 0) +// CHECK: ('offset', 2688) +// CHECK: ('alignment', 0) +// CHECK: ('reloc_offset', 0) +// CHECK: ('num_reloc', 0) +// CHECK: ('flags', 0x10000000) +// CHECK: ('reserved1', 0) +// CHECK: ('reserved2', 0) +// CHECK: ('reserved3', 0) +// CHECK: ), +// CHECK: ('_relocations', [ +// CHECK: ]) +// CHECK: # Section 23 +// CHECK: (('section_name', '__cls_refs\x00\x00\x00\x00\x00\x00') +// CHECK: ('segment_name', '__OBJC\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00') +// CHECK: ('address', 0) +// CHECK: ('size', 0) +// CHECK: ('offset', 2688) +// CHECK: ('alignment', 2) +// CHECK: ('reloc_offset', 0) +// CHECK: ('num_reloc', 0) +// CHECK: ('flags', 0x10000005) +// CHECK: ('reserved1', 0) +// CHECK: ('reserved2', 0) +// CHECK: ('reserved3', 0) +// CHECK: ), +// CHECK: ('_relocations', [ +// CHECK: ]) +// CHECK: # Section 24 +// CHECK: (('section_name', '__message_refs\x00\x00') +// CHECK: ('segment_name', '__OBJC\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00') +// CHECK: ('address', 0) +// CHECK: ('size', 0) +// CHECK: ('offset', 2688) +// CHECK: ('alignment', 2) +// CHECK: ('reloc_offset', 0) +// CHECK: ('num_reloc', 0) +// CHECK: ('flags', 0x10000005) +// CHECK: ('reserved1', 0) +// CHECK: ('reserved2', 0) +// CHECK: ('reserved3', 0) +// CHECK: ), +// CHECK: ('_relocations', [ +// CHECK: ]) +// CHECK: # Section 25 +// CHECK: (('section_name', '__symbols\x00\x00\x00\x00\x00\x00\x00') +// CHECK: ('segment_name', '__OBJC\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00') +// CHECK: ('address', 0) +// CHECK: ('size', 0) +// CHECK: ('offset', 2688) +// CHECK: ('alignment', 0) +// CHECK: ('reloc_offset', 0) +// CHECK: ('num_reloc', 0) +// CHECK: ('flags', 0x10000000) +// CHECK: ('reserved1', 0) +// CHECK: ('reserved2', 0) +// CHECK: ('reserved3', 0) +// CHECK: ), +// CHECK: ('_relocations', [ +// CHECK: ]) +// CHECK: # Section 26 +// CHECK: (('section_name', '__category\x00\x00\x00\x00\x00\x00') +// CHECK: ('segment_name', '__OBJC\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00') +// CHECK: ('address', 0) +// CHECK: ('size', 0) +// CHECK: ('offset', 2688) +// CHECK: ('alignment', 0) +// CHECK: ('reloc_offset', 0) +// CHECK: ('num_reloc', 0) +// CHECK: ('flags', 0x10000000) +// CHECK: ('reserved1', 0) +// CHECK: ('reserved2', 0) +// CHECK: ('reserved3', 0) +// CHECK: ), +// CHECK: ('_relocations', [ +// CHECK: ]) +// CHECK: # Section 27 +// CHECK: (('section_name', '__class_vars\x00\x00\x00\x00') +// CHECK: ('segment_name', '__OBJC\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00') +// CHECK: ('address', 0) +// CHECK: ('size', 0) +// CHECK: ('offset', 2688) +// CHECK: ('alignment', 0) +// CHECK: ('reloc_offset', 0) +// CHECK: ('num_reloc', 0) +// CHECK: ('flags', 0x10000000) +// CHECK: ('reserved1', 0) +// CHECK: ('reserved2', 0) +// CHECK: ('reserved3', 0) +// CHECK: ), +// CHECK: ('_relocations', [ +// CHECK: ]) +// CHECK: # Section 28 +// CHECK: (('section_name', '__instance_vars\x00') +// CHECK: ('segment_name', '__OBJC\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00') +// CHECK: ('address', 0) +// CHECK: ('size', 0) +// CHECK: ('offset', 2688) +// CHECK: ('alignment', 0) +// CHECK: ('reloc_offset', 0) +// CHECK: ('num_reloc', 0) +// CHECK: ('flags', 0x10000000) +// CHECK: ('reserved1', 0) +// CHECK: ('reserved2', 0) +// CHECK: ('reserved3', 0) +// CHECK: ), +// CHECK: ('_relocations', [ +// CHECK: ]) +// CHECK: # Section 29 +// CHECK: (('section_name', '__module_info\x00\x00\x00') +// CHECK: ('segment_name', '__OBJC\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00') +// CHECK: ('address', 0) +// CHECK: ('size', 0) +// CHECK: ('offset', 2688) +// CHECK: ('alignment', 0) +// CHECK: ('reloc_offset', 0) +// CHECK: ('num_reloc', 0) +// CHECK: ('flags', 0x10000000) +// CHECK: ('reserved1', 0) +// CHECK: ('reserved2', 0) +// CHECK: ('reserved3', 0) +// CHECK: ), +// CHECK: ('_relocations', [ +// CHECK: ]) +// CHECK: # Section 30 +// CHECK: (('section_name', '__selector_strs\x00') +// CHECK: ('segment_name', '__OBJC\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00') +// CHECK: ('address', 0) +// CHECK: ('size', 0) +// CHECK: ('offset', 2688) +// CHECK: ('alignment', 0) +// CHECK: ('reloc_offset', 0) +// CHECK: ('num_reloc', 0) +// CHECK: ('flags', 0x2) +// CHECK: ('reserved1', 0) +// CHECK: ('reserved2', 0) +// CHECK: ('reserved3', 0) +// CHECK: ), +// CHECK: ('_relocations', [ +// CHECK: ]) +// CHECK: ]) +// CHECK: ), +// CHECK: # Load Command 1 +// CHECK: (('command', 2) +// CHECK: ('size', 24) +// CHECK: ('symoff', 2688) +// CHECK: ('nsyms', 40) +// CHECK: ('stroff', 3328) +// CHECK: ('strsize', 152) +// CHECK: ('_string_data', '\x00D0\x00D1\x00D2\x00D3\x00L4\x00D4\x00D5\x00D6\x00D7\x00D8\x00D9\x00D12\x00D13\x00D16\x00D17\x00D18\x00D19\x00D20\x00D21\x00D22\x00D23\x00D24\x00D25\x00D26\x00D27\x00D28\x00D29\x00D30\x00D31\x00D32\x00D33\x00D34\x00L35\x00D35\x00L36\x00D36\x00L37\x00D37\x00L38\x00D38\x00\x00\x00') +// CHECK: ('_symbols', [ +// CHECK: # Symbol 0 +// CHECK: (('n_strx', 1) +// CHECK: ('n_type', 0xe) +// CHECK: ('n_sect', 1) +// CHECK: ('n_desc', 0) +// CHECK: ('n_value', 0) +// CHECK: ('_string', 'D0') +// CHECK: ), +// CHECK: # Symbol 1 +// CHECK: (('n_strx', 4) +// CHECK: ('n_type', 0xe) +// CHECK: ('n_sect', 1) +// CHECK: ('n_desc', 0) +// CHECK: ('n_value', 0) +// CHECK: ('_string', 'D1') +// CHECK: ), +// CHECK: # Symbol 2 +// CHECK: (('n_strx', 7) +// CHECK: ('n_type', 0xe) +// CHECK: ('n_sect', 2) +// CHECK: ('n_desc', 0) +// CHECK: ('n_value', 0) +// CHECK: ('_string', 'D2') +// CHECK: ), +// CHECK: # Symbol 3 +// CHECK: (('n_strx', 10) +// CHECK: ('n_type', 0xe) +// CHECK: ('n_sect', 3) +// CHECK: ('n_desc', 0) +// CHECK: ('n_value', 0) +// CHECK: ('_string', 'D3') +// CHECK: ), +// CHECK: # Symbol 4 +// CHECK: (('n_strx', 13) +// CHECK: ('n_type', 0xe) +// CHECK: ('n_sect', 4) +// CHECK: ('n_desc', 0) +// CHECK: ('n_value', 0) +// CHECK: ('_string', 'L4') +// CHECK: ), +// CHECK: # Symbol 5 +// CHECK: (('n_strx', 16) +// CHECK: ('n_type', 0xe) +// CHECK: ('n_sect', 4) +// CHECK: ('n_desc', 0) +// CHECK: ('n_value', 0) +// CHECK: ('_string', 'D4') +// CHECK: ), +// CHECK: # Symbol 6 +// CHECK: (('n_strx', 19) +// CHECK: ('n_type', 0xe) +// CHECK: ('n_sect', 5) +// CHECK: ('n_desc', 0) +// CHECK: ('n_value', 0) +// CHECK: ('_string', 'D5') +// CHECK: ), +// CHECK: # Symbol 7 +// CHECK: (('n_strx', 22) +// CHECK: ('n_type', 0xe) +// CHECK: ('n_sect', 6) +// CHECK: ('n_desc', 0) +// CHECK: ('n_value', 0) +// CHECK: ('_string', 'D6') +// CHECK: ), +// CHECK: # Symbol 8 +// CHECK: (('n_strx', 25) +// CHECK: ('n_type', 0xe) +// CHECK: ('n_sect', 7) +// CHECK: ('n_desc', 0) +// CHECK: ('n_value', 0) +// CHECK: ('_string', 'D7') +// CHECK: ), +// CHECK: # Symbol 9 +// CHECK: (('n_strx', 28) +// CHECK: ('n_type', 0xe) +// CHECK: ('n_sect', 8) +// CHECK: ('n_desc', 0) +// CHECK: ('n_value', 0) +// CHECK: ('_string', 'D8') +// CHECK: ), +// CHECK: # Symbol 10 +// CHECK: (('n_strx', 31) +// CHECK: ('n_type', 0xe) +// CHECK: ('n_sect', 9) +// CHECK: ('n_desc', 0) +// CHECK: ('n_value', 0) +// CHECK: ('_string', 'D9') +// CHECK: ), +// CHECK: # Symbol 11 +// CHECK: (('n_strx', 34) +// CHECK: ('n_type', 0xe) +// CHECK: ('n_sect', 10) +// CHECK: ('n_desc', 0) +// CHECK: ('n_value', 0) +// CHECK: ('_string', 'D12') +// CHECK: ), +// CHECK: # Symbol 12 +// CHECK: (('n_strx', 38) +// CHECK: ('n_type', 0xe) +// CHECK: ('n_sect', 11) +// CHECK: ('n_desc', 0) +// CHECK: ('n_value', 0) +// CHECK: ('_string', 'D13') +// CHECK: ), +// CHECK: # Symbol 13 +// CHECK: (('n_strx', 42) +// CHECK: ('n_type', 0xe) +// CHECK: ('n_sect', 12) +// CHECK: ('n_desc', 0) +// CHECK: ('n_value', 0) +// CHECK: ('_string', 'D16') +// CHECK: ), +// CHECK: # Symbol 14 +// CHECK: (('n_strx', 46) +// CHECK: ('n_type', 0xe) +// CHECK: ('n_sect', 13) +// CHECK: ('n_desc', 0) +// CHECK: ('n_value', 0) +// CHECK: ('_string', 'D17') +// CHECK: ), +// CHECK: # Symbol 15 +// CHECK: (('n_strx', 50) +// CHECK: ('n_type', 0xe) +// CHECK: ('n_sect', 14) +// CHECK: ('n_desc', 0) +// CHECK: ('n_value', 0) +// CHECK: ('_string', 'D18') +// CHECK: ), +// CHECK: # Symbol 16 +// CHECK: (('n_strx', 54) +// CHECK: ('n_type', 0xe) +// CHECK: ('n_sect', 15) +// CHECK: ('n_desc', 0) +// CHECK: ('n_value', 0) +// CHECK: ('_string', 'D19') +// CHECK: ), +// CHECK: # Symbol 17 +// CHECK: (('n_strx', 58) +// CHECK: ('n_type', 0xe) +// CHECK: ('n_sect', 16) +// CHECK: ('n_desc', 0) +// CHECK: ('n_value', 0) +// CHECK: ('_string', 'D20') +// CHECK: ), +// CHECK: # Symbol 18 +// CHECK: (('n_strx', 62) +// CHECK: ('n_type', 0xe) +// CHECK: ('n_sect', 17) +// CHECK: ('n_desc', 0) +// CHECK: ('n_value', 0) +// CHECK: ('_string', 'D21') +// CHECK: ), +// CHECK: # Symbol 19 +// CHECK: (('n_strx', 66) +// CHECK: ('n_type', 0xe) +// CHECK: ('n_sect', 18) +// CHECK: ('n_desc', 0) +// CHECK: ('n_value', 0) +// CHECK: ('_string', 'D22') +// CHECK: ), +// CHECK: # Symbol 20 +// CHECK: (('n_strx', 70) +// CHECK: ('n_type', 0xe) +// CHECK: ('n_sect', 19) +// CHECK: ('n_desc', 0) +// CHECK: ('n_value', 0) +// CHECK: ('_string', 'D23') +// CHECK: ), +// CHECK: # Symbol 21 +// CHECK: (('n_strx', 74) +// CHECK: ('n_type', 0xe) +// CHECK: ('n_sect', 20) +// CHECK: ('n_desc', 0) +// CHECK: ('n_value', 0) +// CHECK: ('_string', 'D24') +// CHECK: ), +// CHECK: # Symbol 22 +// CHECK: (('n_strx', 78) +// CHECK: ('n_type', 0xe) +// CHECK: ('n_sect', 21) +// CHECK: ('n_desc', 0) +// CHECK: ('n_value', 0) +// CHECK: ('_string', 'D25') +// CHECK: ), +// CHECK: # Symbol 23 +// CHECK: (('n_strx', 82) +// CHECK: ('n_type', 0xe) +// CHECK: ('n_sect', 22) +// CHECK: ('n_desc', 0) +// CHECK: ('n_value', 0) +// CHECK: ('_string', 'D26') +// CHECK: ), +// CHECK: # Symbol 24 +// CHECK: (('n_strx', 86) +// CHECK: ('n_type', 0xe) +// CHECK: ('n_sect', 23) +// CHECK: ('n_desc', 0) +// CHECK: ('n_value', 0) +// CHECK: ('_string', 'D27') +// CHECK: ), +// CHECK: # Symbol 25 +// CHECK: (('n_strx', 90) +// CHECK: ('n_type', 0xe) +// CHECK: ('n_sect', 24) +// CHECK: ('n_desc', 0) +// CHECK: ('n_value', 0) +// CHECK: ('_string', 'D28') +// CHECK: ), +// CHECK: # Symbol 26 +// CHECK: (('n_strx', 94) +// CHECK: ('n_type', 0xe) +// CHECK: ('n_sect', 25) +// CHECK: ('n_desc', 0) +// CHECK: ('n_value', 0) +// CHECK: ('_string', 'D29') +// CHECK: ), +// CHECK: # Symbol 27 +// CHECK: (('n_strx', 98) +// CHECK: ('n_type', 0xe) +// CHECK: ('n_sect', 26) +// CHECK: ('n_desc', 0) +// CHECK: ('n_value', 0) +// CHECK: ('_string', 'D30') +// CHECK: ), +// CHECK: # Symbol 28 +// CHECK: (('n_strx', 102) +// CHECK: ('n_type', 0xe) +// CHECK: ('n_sect', 27) +// CHECK: ('n_desc', 0) +// CHECK: ('n_value', 0) +// CHECK: ('_string', 'D31') +// CHECK: ), +// CHECK: # Symbol 29 +// CHECK: (('n_strx', 106) +// CHECK: ('n_type', 0xe) +// CHECK: ('n_sect', 28) +// CHECK: ('n_desc', 0) +// CHECK: ('n_value', 0) +// CHECK: ('_string', 'D32') +// CHECK: ), +// CHECK: # Symbol 30 +// CHECK: (('n_strx', 110) +// CHECK: ('n_type', 0xe) +// CHECK: ('n_sect', 29) +// CHECK: ('n_desc', 0) +// CHECK: ('n_value', 0) +// CHECK: ('_string', 'D33') +// CHECK: ), +// CHECK: # Symbol 31 +// CHECK: (('n_strx', 114) +// CHECK: ('n_type', 0xe) +// CHECK: ('n_sect', 30) +// CHECK: ('n_desc', 0) +// CHECK: ('n_value', 0) +// CHECK: ('_string', 'D34') +// CHECK: ), +// CHECK: # Symbol 32 +// CHECK: (('n_strx', 118) +// CHECK: ('n_type', 0xe) +// CHECK: ('n_sect', 4) +// CHECK: ('n_desc', 0) +// CHECK: ('n_value', 0) +// CHECK: ('_string', 'L35') +// CHECK: ), +// CHECK: # Symbol 33 +// CHECK: (('n_strx', 122) +// CHECK: ('n_type', 0xe) +// CHECK: ('n_sect', 4) +// CHECK: ('n_desc', 0) +// CHECK: ('n_value', 0) +// CHECK: ('_string', 'D35') +// CHECK: ), +// CHECK: # Symbol 34 +// CHECK: (('n_strx', 126) +// CHECK: ('n_type', 0xe) +// CHECK: ('n_sect', 4) +// CHECK: ('n_desc', 0) +// CHECK: ('n_value', 0) +// CHECK: ('_string', 'L36') +// CHECK: ), +// CHECK: # Symbol 35 +// CHECK: (('n_strx', 130) +// CHECK: ('n_type', 0xe) +// CHECK: ('n_sect', 4) +// CHECK: ('n_desc', 0) +// CHECK: ('n_value', 0) +// CHECK: ('_string', 'D36') +// CHECK: ), +// CHECK: # Symbol 36 +// CHECK: (('n_strx', 134) +// CHECK: ('n_type', 0xe) +// CHECK: ('n_sect', 4) +// CHECK: ('n_desc', 0) +// CHECK: ('n_value', 0) +// CHECK: ('_string', 'L37') +// CHECK: ), +// CHECK: # Symbol 37 +// CHECK: (('n_strx', 138) +// CHECK: ('n_type', 0xe) +// CHECK: ('n_sect', 4) +// CHECK: ('n_desc', 0) +// CHECK: ('n_value', 0) +// CHECK: ('_string', 'D37') +// CHECK: ), +// CHECK: # Symbol 38 +// CHECK: (('n_strx', 142) +// CHECK: ('n_type', 0xe) +// CHECK: ('n_sect', 31) +// CHECK: ('n_desc', 0) +// CHECK: ('n_value', 0) +// CHECK: ('_string', 'L38') +// CHECK: ), +// CHECK: # Symbol 39 +// CHECK: (('n_strx', 146) +// CHECK: ('n_type', 0xe) +// CHECK: ('n_sect', 31) +// CHECK: ('n_desc', 0) +// CHECK: ('n_value', 0) +// CHECK: ('_string', 'D38') +// CHECK: ), +// CHECK: ]) +// CHECK: ), +// CHECK: # Load Command 2 +// CHECK: (('command', 11) +// CHECK: ('size', 80) +// CHECK: ('ilocalsym', 0) +// CHECK: ('nlocalsym', 40) +// CHECK: ('iextdefsym', 40) +// CHECK: ('nextdefsym', 0) +// CHECK: ('iundefsym', 40) +// CHECK: ('nundefsym', 0) +// CHECK: ('tocoff', 0) +// CHECK: ('ntoc', 0) +// CHECK: ('modtaboff', 0) +// CHECK: ('nmodtab', 0) +// CHECK: ('extrefsymoff', 0) +// CHECK: ('nextrefsyms', 0) +// CHECK: ('indirectsymoff', 0) +// CHECK: ('nindirectsyms', 0) +// CHECK: ('extreloff', 0) +// CHECK: ('nextrel', 0) +// CHECK: ('locreloff', 0) +// CHECK: ('nlocrel', 0) +// CHECK: ('_indirect_symbols', [ +// CHECK: ]) +// CHECK: ), +// CHECK: ]) From dpatel at apple.com Mon Mar 15 17:23:03 2010 From: dpatel at apple.com (Devang Patel) Date: Mon, 15 Mar 2010 22:23:03 -0000 Subject: [llvm-commits] [llvm] r98584 - /llvm/trunk/lib/Transforms/Scalar/IndVarSimplify.cpp Message-ID: <20100315222303.85A072A6C12C@llvm.org> Author: dpatel Date: Mon Mar 15 17:23:03 2010 New Revision: 98584 URL: http://llvm.org/viewvc/llvm-project?rev=98584&view=rev Log: Skip debug info intrinsics. Modified: llvm/trunk/lib/Transforms/Scalar/IndVarSimplify.cpp Modified: llvm/trunk/lib/Transforms/Scalar/IndVarSimplify.cpp URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Transforms/Scalar/IndVarSimplify.cpp?rev=98584&r1=98583&r2=98584&view=diff ============================================================================== --- llvm/trunk/lib/Transforms/Scalar/IndVarSimplify.cpp (original) +++ llvm/trunk/lib/Transforms/Scalar/IndVarSimplify.cpp Mon Mar 15 17:23:03 2010 @@ -43,6 +43,7 @@ #include "llvm/BasicBlock.h" #include "llvm/Constants.h" #include "llvm/Instructions.h" +#include "llvm/IntrinsicInst.h" #include "llvm/LLVMContext.h" #include "llvm/Type.h" #include "llvm/Analysis/Dominators.h" @@ -556,6 +557,9 @@ // dominates the exit block. if (I->mayHaveSideEffects() || I->mayReadFromMemory()) continue; + // Skip debug info intrinsics. + if (isa(I)) + continue; // Don't sink static AllocaInsts out of the entry block, which would // turn them into dynamic allocas! if (AllocaInst *AI = dyn_cast(I)) From wendling at apple.com Mon Mar 15 17:32:43 2010 From: wendling at apple.com (Bill Wendling) Date: Mon, 15 Mar 2010 15:32:43 -0700 Subject: [llvm-commits] Extract MachObjectWriter class to own header and code files In-Reply-To: <9719867c1003151006r720d53cewebc80de9802ed238@mail.gmail.com> References: <9719867c1003151006r720d53cewebc80de9802ed238@mail.gmail.com> Message-ID: <658792FC-65A6-4812-95A5-F3F6239BFB01@apple.com> On Mar 15, 2010, at 10:06 AM, Aaron Gray wrote: > Hi, > > This patch extracts 'class MachObjectWriter' into its own .h and .cpp files. > > Tested on MSVC and Cygwin. > Hi Aaron, I'll let Chris & Daniel comment on the rest, but: Index: lib/CodeGen/TargetLoweringObjectFileImpl.cpp =================================================================== --- lib/CodeGen/TargetLoweringObjectFileImpl.cpp (revision 98543) +++ lib/CodeGen/TargetLoweringObjectFileImpl.cpp (working copy) @@ -469,6 +469,7 @@ // Otherwise, return a new section. return Entry = MCSectionMachO::Create(Segment, Section, TypeAndAttributes, Reserved2, Kind, getContext()); + assert( Entry != 0 && "MCSectionMachO::Create returns zero"); } The assert is dead code. -bw From bob.wilson at apple.com Mon Mar 15 18:09:18 2010 From: bob.wilson at apple.com (Bob Wilson) Date: Mon, 15 Mar 2010 23:09:18 -0000 Subject: [llvm-commits] [llvm] r98586 - /llvm/trunk/lib/Target/ARM/ARMISelLowering.cpp Message-ID: <20100315230918.D00B12A6C12C@llvm.org> Author: bwilson Date: Mon Mar 15 18:09:18 2010 New Revision: 98586 URL: http://llvm.org/viewvc/llvm-project?rev=98586&view=rev Log: Translate "cc" clobber in ARM inline assembly to ARM::CCRRegisterClass. Radar 7459078. Modified: llvm/trunk/lib/Target/ARM/ARMISelLowering.cpp Modified: llvm/trunk/lib/Target/ARM/ARMISelLowering.cpp URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Target/ARM/ARMISelLowering.cpp?rev=98586&r1=98585&r2=98586&view=diff ============================================================================== --- llvm/trunk/lib/Target/ARM/ARMISelLowering.cpp (original) +++ llvm/trunk/lib/Target/ARM/ARMISelLowering.cpp Mon Mar 15 18:09:18 2010 @@ -4449,6 +4449,9 @@ break; } } + if (StringRef("{cc}").equals_lower(Constraint)) + return std::make_pair(0U, ARM::CCRRegisterClass); + return TargetLowering::getRegForInlineAsmConstraint(Constraint, VT); } From bob.wilson at apple.com Mon Mar 15 18:17:09 2010 From: bob.wilson at apple.com (Bob Wilson) Date: Mon, 15 Mar 2010 16:17:09 -0700 Subject: [llvm-commits] [llvm] r98586 - /llvm/trunk/lib/Target/ARM/ARMISelLowering.cpp In-Reply-To: <20100315230918.D00B12A6C12C@llvm.org> References: <20100315230918.D00B12A6C12C@llvm.org> Message-ID: Someone who understands inline assembly better than I do should take a look at whether something similar is needed for X86 and other targets with condition codes. I don't see anything in the X86 target to handle "cc" clobbers. On Mar 15, 2010, at 4:09 PM, Bob Wilson wrote: > Author: bwilson > Date: Mon Mar 15 18:09:18 2010 > New Revision: 98586 > > URL: http://llvm.org/viewvc/llvm-project?rev=98586&view=rev > Log: > Translate "cc" clobber in ARM inline assembly to ARM::CCRRegisterClass. > Radar 7459078. > > Modified: > llvm/trunk/lib/Target/ARM/ARMISelLowering.cpp > > Modified: llvm/trunk/lib/Target/ARM/ARMISelLowering.cpp > URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Target/ARM/ARMISelLowering.cpp?rev=98586&r1=98585&r2=98586&view=diff > ============================================================================== > --- llvm/trunk/lib/Target/ARM/ARMISelLowering.cpp (original) > +++ llvm/trunk/lib/Target/ARM/ARMISelLowering.cpp Mon Mar 15 18:09:18 2010 > @@ -4449,6 +4449,9 @@ > break; > } > } > + if (StringRef("{cc}").equals_lower(Constraint)) > + return std::make_pair(0U, ARM::CCRRegisterClass); > + > return TargetLowering::getRegForInlineAsmConstraint(Constraint, VT); > } > > > > _______________________________________________ > llvm-commits mailing list > llvm-commits at cs.uiuc.edu > http://lists.cs.uiuc.edu/mailman/listinfo/llvm-commits From gohman at apple.com Mon Mar 15 18:23:03 2010 From: gohman at apple.com (Dan Gohman) Date: Mon, 15 Mar 2010 23:23:03 -0000 Subject: [llvm-commits] [llvm] r98588 - in /llvm/trunk: lib/Target/X86/X86ISelLowering.cpp test/CodeGen/X86/gather-addresses.ll Message-ID: <20100315232303.85E9D2A6C12D@llvm.org> Author: djg Date: Mon Mar 15 18:23:03 2010 New Revision: 98588 URL: http://llvm.org/viewvc/llvm-project?rev=98588&view=rev Log: Recognize code for doing vector gather/scatter index calculations with 32-bit indices. Instead of shuffling each element out of the index vector, when all indices are needed, just store the input vector to the stack and load the elements out. Added: llvm/trunk/test/CodeGen/X86/gather-addresses.ll Modified: llvm/trunk/lib/Target/X86/X86ISelLowering.cpp Modified: llvm/trunk/lib/Target/X86/X86ISelLowering.cpp URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Target/X86/X86ISelLowering.cpp?rev=98588&r1=98587&r2=98588&view=diff ============================================================================== --- llvm/trunk/lib/Target/X86/X86ISelLowering.cpp (original) +++ llvm/trunk/lib/Target/X86/X86ISelLowering.cpp Mon Mar 15 18:23:03 2010 @@ -990,6 +990,7 @@ // We have target-specific dag combine patterns for the following nodes: setTargetDAGCombine(ISD::VECTOR_SHUFFLE); + setTargetDAGCombine(ISD::EXTRACT_VECTOR_ELT); setTargetDAGCombine(ISD::BUILD_VECTOR); setTargetDAGCombine(ISD::SELECT); setTargetDAGCombine(ISD::SHL); @@ -8853,6 +8854,87 @@ return SDValue(); } +/// PerformShuffleCombine - Detect vector gather/scatter index generation +/// and convert it from being a bunch of shuffles and extracts to a simple +/// store and scalar loads to extract the elements. +static SDValue PerformEXTRACT_VECTOR_ELTCombine(SDNode *N, SelectionDAG &DAG, + const TargetLowering &TLI) { + SDValue InputVector = N->getOperand(0); + + // Only operate on vectors of 4 elements, where the alternative shuffling + // gets to be more expensive. + if (InputVector.getValueType() != MVT::v4i32) + return SDValue(); + + // Check whether every use of InputVector is an EXTRACT_VECTOR_ELT with a + // single use which is a sign-extend or zero-extend, and all elements are + // used. + SmallVector Uses; + unsigned ExtractedElements = 0; + for (SDNode::use_iterator UI = InputVector.getNode()->use_begin(), + UE = InputVector.getNode()->use_end(); UI != UE; ++UI) { + if (UI.getUse().getResNo() != InputVector.getResNo()) + return SDValue(); + + SDNode *Extract = *UI; + if (Extract->getOpcode() != ISD::EXTRACT_VECTOR_ELT) + return SDValue(); + + if (Extract->getValueType(0) != MVT::i32) + return SDValue(); + if (!Extract->hasOneUse()) + return SDValue(); + if (Extract->use_begin()->getOpcode() != ISD::SIGN_EXTEND && + Extract->use_begin()->getOpcode() != ISD::ZERO_EXTEND) + return SDValue(); + if (!isa(Extract->getOperand(1))) + return SDValue(); + + // Record which element was extracted. + ExtractedElements |= + 1 << cast(Extract->getOperand(1))->getZExtValue(); + + Uses.push_back(Extract); + } + + // If not all the elements were used, this may not be worthwhile. + if (ExtractedElements != 15) + return SDValue(); + + // Ok, we've now decided to do the transformation. + DebugLoc dl = InputVector.getDebugLoc(); + + // Store the value to a temporary stack slot. + SDValue StackPtr = DAG.CreateStackTemporary(InputVector.getValueType()); + SDValue Ch = DAG.getStore(DAG.getEntryNode(), dl, InputVector, StackPtr, NULL, 0, + false, false, 0); + + // Replace each use (extract) with a load of the appropriate element. + for (SmallVectorImpl::iterator UI = Uses.begin(), + UE = Uses.end(); UI != UE; ++UI) { + SDNode *Extract = *UI; + + // Compute the element's address. + SDValue Idx = Extract->getOperand(1); + unsigned EltSize = + InputVector.getValueType().getVectorElementType().getSizeInBits()/8; + uint64_t Offset = EltSize * cast(Idx)->getZExtValue(); + SDValue OffsetVal = DAG.getConstant(Offset, TLI.getPointerTy()); + + SDValue ScalarAddr = DAG.getNode(ISD::ADD, dl, Idx.getValueType(), OffsetVal, StackPtr); + + // Load the scalar. + SDValue LoadScalar = DAG.getLoad(Extract->getValueType(0), dl, Ch, ScalarAddr, + NULL, 0, false, false, 0); + + // Replace the exact with the load. + DAG.ReplaceAllUsesOfValueWith(SDValue(Extract, 0), LoadScalar); + } + + // The replacement was made in place; don't return anything. + return SDValue(); +} + /// PerformSELECTCombine - Do target-specific dag combines on SELECT nodes. static SDValue PerformSELECTCombine(SDNode *N, SelectionDAG &DAG, const X86Subtarget *Subtarget) { @@ -9742,6 +9824,8 @@ switch (N->getOpcode()) { default: break; case ISD::VECTOR_SHUFFLE: return PerformShuffleCombine(N, DAG, *this); + case ISD::EXTRACT_VECTOR_ELT: + return PerformEXTRACT_VECTOR_ELTCombine(N, DAG, *this); case ISD::SELECT: return PerformSELECTCombine(N, DAG, Subtarget); case X86ISD::CMOV: return PerformCMOVCombine(N, DAG, DCI); case ISD::MUL: return PerformMulCombine(N, DAG, DCI); Added: llvm/trunk/test/CodeGen/X86/gather-addresses.ll URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/CodeGen/X86/gather-addresses.ll?rev=98588&view=auto ============================================================================== --- llvm/trunk/test/CodeGen/X86/gather-addresses.ll (added) +++ llvm/trunk/test/CodeGen/X86/gather-addresses.ll Mon Mar 15 18:23:03 2010 @@ -0,0 +1,39 @@ +; RUN: llc -march=x86-64 < %s | FileCheck %s + +; When doing vector gather-scatter index calculation with 32-bit indices, +; bounce the vector off of cache rather than shuffling each individual +; element out of the index vector. + +; CHECK: pand (%rdx), %xmm0 +; CHECK: movaps %xmm0, -24(%rsp) +; CHECK: movslq -24(%rsp), %rax +; CHECK: movsd (%rdi,%rax,8), %xmm0 +; CHECK: movslq -20(%rsp), %rax +; CHECK: movhpd (%rdi,%rax,8), %xmm0 +; CHECK: movslq -16(%rsp), %rax +; CHECK: movsd (%rdi,%rax,8), %xmm1 +; CHECK: movslq -12(%rsp), %rax +; CHECK: movhpd (%rdi,%rax,8), %xmm1 + +define <4 x double> @foo(double* %p, <4 x i32>* %i, <4 x i32>* %h) nounwind { + %a = load <4 x i32>* %i + %b = load <4 x i32>* %h + %j = and <4 x i32> %a, %b + %d0 = extractelement <4 x i32> %j, i32 0 + %d1 = extractelement <4 x i32> %j, i32 1 + %d2 = extractelement <4 x i32> %j, i32 2 + %d3 = extractelement <4 x i32> %j, i32 3 + %q0 = getelementptr double* %p, i32 %d0 + %q1 = getelementptr double* %p, i32 %d1 + %q2 = getelementptr double* %p, i32 %d2 + %q3 = getelementptr double* %p, i32 %d3 + %r0 = load double* %q0 + %r1 = load double* %q1 + %r2 = load double* %q2 + %r3 = load double* %q3 + %v0 = insertelement <4 x double> undef, double %r0, i32 0 + %v1 = insertelement <4 x double> %v0, double %r1, i32 1 + %v2 = insertelement <4 x double> %v1, double %r2, i32 2 + %v3 = insertelement <4 x double> %v2, double %r3, i32 3 + ret <4 x double> %v3 +} From daniel at zuster.org Mon Mar 15 18:51:06 2010 From: daniel at zuster.org (Daniel Dunbar) Date: Mon, 15 Mar 2010 23:51:06 -0000 Subject: [llvm-commits] [llvm] r98592 - in /llvm/trunk: include/llvm/MC/MCExpr.h lib/MC/MCExpr.cpp lib/MC/MCParser/AsmParser.cpp lib/Target/X86/AsmPrinter/X86MCInstLower.cpp lib/Target/X86/CMakeLists.txt lib/Target/X86/X86ISelLowering.cpp lib/Target/X86/X86MCTargetExpr.cpp lib/Target/X86/X86MCTargetExpr.h lib/Target/X86/X86TargetObjectFile.cpp test/CodeGen/X86/personality.ll Message-ID: <20100315235106.E624B2A6C12C@llvm.org> Author: ddunbar Date: Mon Mar 15 18:51:06 2010 New Revision: 98592 URL: http://llvm.org/viewvc/llvm-project?rev=98592&view=rev Log: MC: Allow modifiers in MCSymbolRefExpr, and eliminate X86MCTargetExpr. - Although it would be nice to allow this decoupling, the assembler needs to be able to reason about MCSymbolRefExprs in too many places to make this viable. We can use a target specific encoding of the variant if this becomes an issue. - This patch also extends llvm-mc to support parsing of the modifiers, as opposed to lumping them in with the symbol. Removed: llvm/trunk/lib/Target/X86/X86MCTargetExpr.cpp llvm/trunk/lib/Target/X86/X86MCTargetExpr.h Modified: llvm/trunk/include/llvm/MC/MCExpr.h llvm/trunk/lib/MC/MCExpr.cpp llvm/trunk/lib/MC/MCParser/AsmParser.cpp llvm/trunk/lib/Target/X86/AsmPrinter/X86MCInstLower.cpp llvm/trunk/lib/Target/X86/CMakeLists.txt llvm/trunk/lib/Target/X86/X86ISelLowering.cpp llvm/trunk/lib/Target/X86/X86TargetObjectFile.cpp llvm/trunk/test/CodeGen/X86/personality.ll Modified: llvm/trunk/include/llvm/MC/MCExpr.h URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/MC/MCExpr.h?rev=98592&r1=98591&r2=98592&view=diff ============================================================================== --- llvm/trunk/include/llvm/MC/MCExpr.h (original) +++ llvm/trunk/include/llvm/MC/MCExpr.h Mon Mar 15 18:51:06 2010 @@ -121,21 +121,49 @@ /// assembler variable (defined constant), or constitute an implicit definition /// of the symbol as external. class MCSymbolRefExpr : public MCExpr { +public: + enum VariantKind { + VK_None, + VK_Invalid, + + VK_GOT, + VK_GOTOFF, + VK_GOTPCREL, + VK_GOTTPOFF, + VK_INDNTPOFF, + VK_NTPOFF, + VK_PLT, + VK_TLSGD, + VK_TPOFF + }; + +private: + /// The symbol being referenced. const MCSymbol *Symbol; - explicit MCSymbolRefExpr(const MCSymbol *_Symbol) - : MCExpr(MCExpr::SymbolRef), Symbol(_Symbol) {} + /// The symbol reference modifier. + const VariantKind Kind; + + explicit MCSymbolRefExpr(const MCSymbol *_Symbol, VariantKind _Kind) + : MCExpr(MCExpr::SymbolRef), Symbol(_Symbol), Kind(_Kind) {} public: /// @name Construction /// @{ - static const MCSymbolRefExpr *Create(const MCSymbol *Symbol, MCContext &Ctx); - static const MCSymbolRefExpr *Create(StringRef Name, MCContext &Ctx); + static const MCSymbolRefExpr *Create(const MCSymbol *Symbol, MCContext &Ctx) { + return MCSymbolRefExpr::Create(Symbol, VK_None, Ctx); + } + + static const MCSymbolRefExpr *Create(const MCSymbol *Symbol, VariantKind Kind, + MCContext &Ctx); + static const MCSymbolRefExpr *Create(StringRef Name, VariantKind Kind, + MCContext &Ctx); /// CreateTemp - Create a reference to an assembler temporary label with the /// specified name. - static const MCSymbolRefExpr *CreateTemp(StringRef Name, MCContext &Ctx); + static const MCSymbolRefExpr *CreateTemp(StringRef Name, VariantKind Kind, + MCContext &Ctx); /// @} /// @name Accessors @@ -143,6 +171,16 @@ const MCSymbol &getSymbol() const { return *Symbol; } + VariantKind getKind() const { return Kind; } + + /// @} + /// @name Static Utility Functions + /// @{ + + static StringRef getVariantKindName(VariantKind Kind); + + static VariantKind getVariantKindForName(StringRef Name); + /// @} static bool classof(const MCExpr *E) { Modified: llvm/trunk/lib/MC/MCExpr.cpp URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/MC/MCExpr.cpp?rev=98592&r1=98591&r2=98592&view=diff ============================================================================== --- llvm/trunk/lib/MC/MCExpr.cpp (original) +++ llvm/trunk/lib/MC/MCExpr.cpp Mon Mar 15 18:51:06 2010 @@ -8,6 +8,7 @@ //===----------------------------------------------------------------------===// #include "llvm/MC/MCExpr.h" +#include "llvm/ADT/StringSwitch.h" #include "llvm/MC/MCAsmLayout.h" #include "llvm/MC/MCAssembler.h" #include "llvm/MC/MCContext.h" @@ -27,7 +28,8 @@ return; case MCExpr::SymbolRef: { - const MCSymbol &Sym = cast(*this).getSymbol(); + const MCSymbolRefExpr &SRE = cast(*this); + const MCSymbol &Sym = SRE.getSymbol(); // Parenthesize names that start with $ so that they don't look like // absolute names. @@ -35,6 +37,10 @@ OS << '(' << Sym << ')'; else OS << Sym; + + if (SRE.getKind() != MCSymbolRefExpr::VK_None) + OS << '@' << MCSymbolRefExpr::getVariantKindName(SRE.getKind()); + return; } @@ -127,20 +133,60 @@ return new (Ctx) MCConstantExpr(Value); } +/* *** */ + const MCSymbolRefExpr *MCSymbolRefExpr::Create(const MCSymbol *Sym, + VariantKind Kind, MCContext &Ctx) { - return new (Ctx) MCSymbolRefExpr(Sym); + return new (Ctx) MCSymbolRefExpr(Sym, Kind); } -const MCSymbolRefExpr *MCSymbolRefExpr::Create(StringRef Name, MCContext &Ctx) { - return Create(Ctx.GetOrCreateSymbol(Name), Ctx); +const MCSymbolRefExpr *MCSymbolRefExpr::Create(StringRef Name, VariantKind Kind, + MCContext &Ctx) { + return Create(Ctx.GetOrCreateSymbol(Name), Kind, Ctx); } const MCSymbolRefExpr *MCSymbolRefExpr::CreateTemp(StringRef Name, + VariantKind Kind, MCContext &Ctx) { - return Create(Ctx.GetOrCreateTemporarySymbol(Name), Ctx); + return Create(Ctx.GetOrCreateTemporarySymbol(Name), Kind, Ctx); +} + +StringRef MCSymbolRefExpr::getVariantKindName(VariantKind Kind) { + switch (Kind) { + default: + case VK_Invalid: return "<>"; + case VK_None: return "<>"; + + case VK_GOT: return "GOT"; + case VK_GOTOFF: return "GOTOFF"; + case VK_GOTPCREL: return "GOTPCREL"; + case VK_GOTTPOFF: return "GOTTPOFF"; + case VK_INDNTPOFF: return "INDNTPOFF"; + case VK_NTPOFF: return "NTPOFF"; + case VK_PLT: return "PLT"; + case VK_TLSGD: return "TLSGD"; + case VK_TPOFF: return "TPOFF"; + } +} + +MCSymbolRefExpr::VariantKind +MCSymbolRefExpr::getVariantKindForName(StringRef Name) { + return StringSwitch(Name) + .Case("GOT", VK_GOT) + .Case("GOTOFF", VK_GOTOFF) + .Case("GOTPCREL", VK_GOTPCREL) + .Case("GOTTPOFF", VK_GOTTPOFF) + .Case("INDNTPOFF", VK_INDNTPOFF) + .Case("NTPOFF", VK_NTPOFF) + .Case("PLT", VK_PLT) + .Case("TLSGD", VK_TLSGD) + .Case("TPOFF", VK_TPOFF) + .Default(VK_Invalid); } +/* *** */ + void MCTargetExpr::Anchor() {} /* *** */ Modified: llvm/trunk/lib/MC/MCParser/AsmParser.cpp URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/MC/MCParser/AsmParser.cpp?rev=98592&r1=98591&r2=98592&view=diff ============================================================================== --- llvm/trunk/lib/MC/MCParser/AsmParser.cpp (original) +++ llvm/trunk/lib/MC/MCParser/AsmParser.cpp Mon Mar 15 18:51:06 2010 @@ -262,19 +262,29 @@ case AsmToken::String: case AsmToken::Identifier: { // This is a symbol reference. - MCSymbol *Sym = CreateSymbol(getTok().getIdentifier()); + std::pair Split = getTok().getIdentifier().split('@'); + MCSymbol *Sym = CreateSymbol(Split.first); + + // Lookup the symbol variant if used. + MCSymbolRefExpr::VariantKind Variant = MCSymbolRefExpr::VK_None; + if (Split.first.size() != getTok().getIdentifier().size()) + Variant = MCSymbolRefExpr::getVariantKindForName(Split.second); + EndLoc = Lexer.getLoc(); Lex(); // Eat identifier. // If this is an absolute variable reference, substitute it now to preserve // semantics in the face of reassignment. if (Sym->getValue() && isa(Sym->getValue())) { + if (Variant) + return Error(EndLoc, "unexpected modified on variable reference"); + Res = Sym->getValue(); return false; } // Otherwise create a symbol ref. - Res = MCSymbolRefExpr::Create(Sym, getContext()); + Res = MCSymbolRefExpr::Create(Sym, Variant, getContext()); return false; } case AsmToken::Integer: Modified: llvm/trunk/lib/Target/X86/AsmPrinter/X86MCInstLower.cpp URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Target/X86/AsmPrinter/X86MCInstLower.cpp?rev=98592&r1=98591&r2=98592&view=diff ============================================================================== --- llvm/trunk/lib/Target/X86/AsmPrinter/X86MCInstLower.cpp (original) +++ llvm/trunk/lib/Target/X86/AsmPrinter/X86MCInstLower.cpp Mon Mar 15 18:51:06 2010 @@ -16,7 +16,6 @@ #include "X86AsmPrinter.h" #include "X86COFFMachineModuleInfo.h" #include "X86MCAsmInfo.h" -#include "X86MCTargetExpr.h" #include "llvm/Analysis/DebugInfo.h" #include "llvm/CodeGen/MachineModuleInfoImpls.h" #include "llvm/MC/MCContext.h" @@ -142,7 +141,7 @@ // FIXME: We would like an efficient form for this, so we don't have to do a // lot of extra uniquing. const MCExpr *Expr = 0; - X86MCTargetExpr::VariantKind RefKind = X86MCTargetExpr::Invalid; + MCSymbolRefExpr::VariantKind RefKind = MCSymbolRefExpr::VK_None; switch (MO.getTargetFlags()) { default: llvm_unreachable("Unknown target flag on GV operand"); @@ -153,15 +152,15 @@ case X86II::MO_DARWIN_STUB: break; - case X86II::MO_TLSGD: RefKind = X86MCTargetExpr::TLSGD; break; - case X86II::MO_GOTTPOFF: RefKind = X86MCTargetExpr::GOTTPOFF; break; - case X86II::MO_INDNTPOFF: RefKind = X86MCTargetExpr::INDNTPOFF; break; - case X86II::MO_TPOFF: RefKind = X86MCTargetExpr::TPOFF; break; - case X86II::MO_NTPOFF: RefKind = X86MCTargetExpr::NTPOFF; break; - case X86II::MO_GOTPCREL: RefKind = X86MCTargetExpr::GOTPCREL; break; - case X86II::MO_GOT: RefKind = X86MCTargetExpr::GOT; break; - case X86II::MO_GOTOFF: RefKind = X86MCTargetExpr::GOTOFF; break; - case X86II::MO_PLT: RefKind = X86MCTargetExpr::PLT; break; + case X86II::MO_TLSGD: RefKind = MCSymbolRefExpr::VK_TLSGD; break; + case X86II::MO_GOTTPOFF: RefKind = MCSymbolRefExpr::VK_GOTTPOFF; break; + case X86II::MO_INDNTPOFF: RefKind = MCSymbolRefExpr::VK_INDNTPOFF; break; + case X86II::MO_TPOFF: RefKind = MCSymbolRefExpr::VK_TPOFF; break; + case X86II::MO_NTPOFF: RefKind = MCSymbolRefExpr::VK_NTPOFF; break; + case X86II::MO_GOTPCREL: RefKind = MCSymbolRefExpr::VK_GOTPCREL; break; + case X86II::MO_GOT: RefKind = MCSymbolRefExpr::VK_GOT; break; + case X86II::MO_GOTOFF: RefKind = MCSymbolRefExpr::VK_GOTOFF; break; + case X86II::MO_PLT: RefKind = MCSymbolRefExpr::VK_PLT; break; case X86II::MO_PIC_BASE_OFFSET: case X86II::MO_DARWIN_NONLAZY_PIC_BASE: case X86II::MO_DARWIN_HIDDEN_NONLAZY_PIC_BASE: @@ -173,12 +172,8 @@ break; } - if (Expr == 0) { - if (RefKind == X86MCTargetExpr::Invalid) - Expr = MCSymbolRefExpr::Create(Sym, Ctx); - else - Expr = X86MCTargetExpr::Create(Sym, RefKind, Ctx); - } + if (Expr == 0) + Expr = MCSymbolRefExpr::Create(Sym, RefKind, Ctx); if (!MO.isJTI() && MO.getOffset()) Expr = MCBinaryExpr::CreateAdd(Expr, Modified: llvm/trunk/lib/Target/X86/CMakeLists.txt URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Target/X86/CMakeLists.txt?rev=98592&r1=98591&r2=98592&view=diff ============================================================================== --- llvm/trunk/lib/Target/X86/CMakeLists.txt (original) +++ llvm/trunk/lib/Target/X86/CMakeLists.txt Mon Mar 15 18:51:06 2010 @@ -27,7 +27,6 @@ X86JITInfo.cpp X86MCAsmInfo.cpp X86MCCodeEmitter.cpp - X86MCTargetExpr.cpp X86RegisterInfo.cpp X86Subtarget.cpp X86TargetMachine.cpp Modified: llvm/trunk/lib/Target/X86/X86ISelLowering.cpp URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Target/X86/X86ISelLowering.cpp?rev=98592&r1=98591&r2=98592&view=diff ============================================================================== --- llvm/trunk/lib/Target/X86/X86ISelLowering.cpp (original) +++ llvm/trunk/lib/Target/X86/X86ISelLowering.cpp Mon Mar 15 18:51:06 2010 @@ -16,7 +16,6 @@ #include "X86.h" #include "X86InstrBuilder.h" #include "X86ISelLowering.h" -#include "X86MCTargetExpr.h" #include "X86TargetMachine.h" #include "X86TargetObjectFile.h" #include "llvm/CallingConv.h" @@ -37,6 +36,7 @@ #include "llvm/CodeGen/PseudoSourceValue.h" #include "llvm/MC/MCAsmInfo.h" #include "llvm/MC/MCContext.h" +#include "llvm/MC/MCExpr.h" #include "llvm/MC/MCSymbol.h" #include "llvm/ADT/BitVector.h" #include "llvm/ADT/SmallSet.h" @@ -1121,8 +1121,8 @@ Subtarget->isPICStyleGOT()); // In 32-bit ELF systems, our jump table entries are formed with @GOTOFF // entries. - return X86MCTargetExpr::Create(MBB->getSymbol(), - X86MCTargetExpr::GOTOFF, Ctx); + return MCSymbolRefExpr::Create(MBB->getSymbol(), + MCSymbolRefExpr::VK_GOTOFF, Ctx); } /// getPICJumpTableRelocaBase - Returns relocation base for the given PIC Removed: llvm/trunk/lib/Target/X86/X86MCTargetExpr.cpp URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Target/X86/X86MCTargetExpr.cpp?rev=98591&view=auto ============================================================================== --- llvm/trunk/lib/Target/X86/X86MCTargetExpr.cpp (original) +++ llvm/trunk/lib/Target/X86/X86MCTargetExpr.cpp (removed) @@ -1,49 +0,0 @@ -//===- X86MCTargetExpr.cpp - X86 Target Specific MCExpr Implementation ----===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// - -#include "X86MCTargetExpr.h" -#include "llvm/MC/MCContext.h" -#include "llvm/MC/MCSymbol.h" -#include "llvm/MC/MCValue.h" -#include "llvm/Support/raw_ostream.h" -using namespace llvm; - -X86MCTargetExpr *X86MCTargetExpr::Create(const MCSymbol *Sym, VariantKind K, - MCContext &Ctx) { - return new (Ctx) X86MCTargetExpr(Sym, K); -} - -void X86MCTargetExpr::PrintImpl(raw_ostream &OS) const { - OS << *Sym; - - switch (Kind) { - case Invalid: OS << "@"; break; - case GOT: OS << "@GOT"; break; - case GOTOFF: OS << "@GOTOFF"; break; - case GOTPCREL: OS << "@GOTPCREL"; break; - case GOTTPOFF: OS << "@GOTTPOFF"; break; - case INDNTPOFF: OS << "@INDNTPOFF"; break; - case NTPOFF: OS << "@NTPOFF"; break; - case PLT: OS << "@PLT"; break; - case TLSGD: OS << "@TLSGD"; break; - case TPOFF: OS << "@TPOFF"; break; - } -} - -bool X86MCTargetExpr::EvaluateAsRelocatableImpl(MCValue &Res, - const MCAsmLayout *Layout) const { - // FIXME: I don't know if this is right, it followed MCSymbolRefExpr. - - // Evaluate recursively if this is a variable. - if (Sym->isVariable()) - return Sym->getValue()->EvaluateAsRelocatable(Res, Layout); - - Res = MCValue::get(Sym, 0, 0); - return true; -} Removed: llvm/trunk/lib/Target/X86/X86MCTargetExpr.h URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Target/X86/X86MCTargetExpr.h?rev=98591&view=auto ============================================================================== --- llvm/trunk/lib/Target/X86/X86MCTargetExpr.h (original) +++ llvm/trunk/lib/Target/X86/X86MCTargetExpr.h (removed) @@ -1,49 +0,0 @@ -//===- X86MCTargetExpr.h - X86 Target Specific MCExpr -----------*- C++ -*-===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// - -#ifndef X86_MCTARGETEXPR_H -#define X86_MCTARGETEXPR_H - -#include "llvm/MC/MCExpr.h" - -namespace llvm { - -/// X86MCTargetExpr - This class represents symbol variants, like foo at GOT. -class X86MCTargetExpr : public MCTargetExpr { -public: - enum VariantKind { - Invalid, - GOT, - GOTOFF, - GOTPCREL, - GOTTPOFF, - INDNTPOFF, - NTPOFF, - PLT, - TLSGD, - TPOFF - }; -private: - /// Sym - The symbol being referenced. - const MCSymbol * const Sym; - /// Kind - The modifier. - const VariantKind Kind; - - X86MCTargetExpr(const MCSymbol *S, VariantKind K) : Sym(S), Kind(K) {} -public: - static X86MCTargetExpr *Create(const MCSymbol *Sym, VariantKind K, - MCContext &Ctx); - - void PrintImpl(raw_ostream &OS) const; - bool EvaluateAsRelocatableImpl(MCValue &Res, const MCAsmLayout *Layout) const; -}; - -} // end namespace llvm - -#endif Modified: llvm/trunk/lib/Target/X86/X86TargetObjectFile.cpp URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Target/X86/X86TargetObjectFile.cpp?rev=98592&r1=98591&r2=98592&view=diff ============================================================================== --- llvm/trunk/lib/Target/X86/X86TargetObjectFile.cpp (original) +++ llvm/trunk/lib/Target/X86/X86TargetObjectFile.cpp Mon Mar 15 18:51:06 2010 @@ -7,11 +7,11 @@ // //===----------------------------------------------------------------------===// -#include "X86MCTargetExpr.h" #include "X86TargetObjectFile.h" #include "X86TargetMachine.h" #include "llvm/CodeGen/MachineModuleInfoImpls.h" #include "llvm/MC/MCContext.h" +#include "llvm/MC/MCExpr.h" #include "llvm/MC/MCSectionMachO.h" #include "llvm/Target/Mangler.h" #include "llvm/ADT/SmallString.h" @@ -29,7 +29,7 @@ if (Encoding & (DW_EH_PE_indirect | DW_EH_PE_pcrel)) { const MCSymbol *Sym = Mang->getSymbol(GV); const MCExpr *Res = - X86MCTargetExpr::Create(Sym, X86MCTargetExpr::GOTPCREL, getContext()); + MCSymbolRefExpr::Create(Sym, MCSymbolRefExpr::VK_GOTPCREL, getContext()); const MCExpr *Four = MCConstantExpr::Create(4, getContext()); return MCBinaryExpr::CreateAdd(Res, Four, getContext()); } Modified: llvm/trunk/test/CodeGen/X86/personality.ll URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/CodeGen/X86/personality.ll?rev=98592&r1=98591&r2=98592&view=diff ============================================================================== --- llvm/trunk/test/CodeGen/X86/personality.ll (original) +++ llvm/trunk/test/CodeGen/X86/personality.ll Mon Mar 15 18:51:06 2010 @@ -39,7 +39,7 @@ declare void @__cxa_end_catch() ; X64: Leh_frame_common_begin: -; X64: .long (___gxx_personality_v0 at GOTPCREL)+4 +; X64: .long ___gxx_personality_v0 at GOTPCREL+4 ; X32: Leh_frame_common_begin: ; X32: .long L___gxx_personality_v0$non_lazy_ptr- From aaronngray.lists at googlemail.com Mon Mar 15 19:09:53 2010 From: aaronngray.lists at googlemail.com (Aaron Gray) Date: Tue, 16 Mar 2010 00:09:53 +0000 Subject: [llvm-commits] Extract MachObjectWriter class to own header and code files In-Reply-To: <658792FC-65A6-4812-95A5-F3F6239BFB01@apple.com> References: <9719867c1003151006r720d53cewebc80de9802ed238@mail.gmail.com> <658792FC-65A6-4812-95A5-F3F6239BFB01@apple.com> Message-ID: <9719867c1003151709t690566f1g56eaefa2586b32a8@mail.gmail.com> On 15 March 2010 22:32, Bill Wendling wrote: > On Mar 15, 2010, at 10:06 AM, Aaron Gray wrote: > > > Hi, > > > > This patch extracts 'class MachObjectWriter' into its own .h and .cpp > files. > > > > Tested on MSVC and Cygwin. > > > Hi Aaron, > > I'll let Chris & Daniel comment on the rest, but: > > Index: lib/CodeGen/TargetLoweringObjectFileImpl.cpp > =================================================================== > --- lib/CodeGen/TargetLoweringObjectFileImpl.cpp (revision 98543) > +++ lib/CodeGen/TargetLoweringObjectFileImpl.cpp (working copy) > @@ -469,6 +469,7 @@ > // Otherwise, return a new section. > return Entry = MCSectionMachO::Create(Segment, Section, > TypeAndAttributes, > Reserved2, Kind, getContext()); > + assert( Entry != 0 && "MCSectionMachO::Create returns zero"); > } > > The assert is dead code. Yes, that is not very good, I thought I had got rid of that :( Aaron -------------- next part -------------- An HTML attachment was scrubbed... URL: http://lists.cs.uiuc.edu/pipermail/llvm-commits/attachments/20100316/921416b0/attachment.html From sabre at nondot.org Mon Mar 15 19:29:39 2010 From: sabre at nondot.org (Chris Lattner) Date: Tue, 16 Mar 2010 00:29:39 -0000 Subject: [llvm-commits] [llvm] r98595 - in /llvm/trunk: include/llvm/CodeGen/MachineModuleInfo.h lib/CodeGen/AsmPrinter/AsmPrinter.cpp lib/CodeGen/MachineModuleInfo.cpp test/CodeGen/Generic/addr-label.ll Message-ID: <20100316002939.905642A6C12C@llvm.org> Author: lattner Date: Mon Mar 15 19:29:39 2010 New Revision: 98595 URL: http://llvm.org/viewvc/llvm-project?rev=98595&view=rev Log: Fix the third (and last known) case of code update problems due to LLVM IR changes with addr label weirdness. In the testcase, we generate references to the two bb's when codegen'ing the first function: _test1: ## @test1 leaq Ltmp0(%rip), %rax .. leaq Ltmp1(%rip), %rax Then continue to codegen the second function where the blocks get merged. We're now smart enough to emit both labels, producing this code: _test_fun: ## @test_fun ## BB#0: ## %entry Ltmp1: ## Block address taken Ltmp0: ## BB#1: ## %ret movl $-1, %eax ret Rejoice. Modified: llvm/trunk/include/llvm/CodeGen/MachineModuleInfo.h llvm/trunk/lib/CodeGen/AsmPrinter/AsmPrinter.cpp llvm/trunk/lib/CodeGen/MachineModuleInfo.cpp llvm/trunk/test/CodeGen/Generic/addr-label.ll Modified: llvm/trunk/include/llvm/CodeGen/MachineModuleInfo.h URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/CodeGen/MachineModuleInfo.h?rev=98595&r1=98594&r2=98595&view=diff ============================================================================== --- llvm/trunk/include/llvm/CodeGen/MachineModuleInfo.h (original) +++ llvm/trunk/include/llvm/CodeGen/MachineModuleInfo.h Mon Mar 15 19:29:39 2010 @@ -215,6 +215,11 @@ /// because the block may be accessed outside its containing function. MCSymbol *getAddrLabelSymbol(const BasicBlock *BB); + /// getAddrLabelSymbolToEmit - Return the symbol to be used for the specified + /// basic block when its address is taken. If other blocks were RAUW'd to + /// this one, we may have to emit them as well, return the whole set. + std::vector getAddrLabelSymbolToEmit(const BasicBlock *BB); + /// takeDeletedSymbolsForFunction - If the specified function has had any /// references to address-taken blocks generated, but the block got deleted, /// return the symbol now so we can emit it. This prevents emitting a Modified: llvm/trunk/lib/CodeGen/AsmPrinter/AsmPrinter.cpp URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/CodeGen/AsmPrinter/AsmPrinter.cpp?rev=98595&r1=98594&r2=98595&view=diff ============================================================================== --- llvm/trunk/lib/CodeGen/AsmPrinter/AsmPrinter.cpp (original) +++ llvm/trunk/lib/CodeGen/AsmPrinter/AsmPrinter.cpp Mon Mar 15 19:29:39 2010 @@ -1709,16 +1709,19 @@ if (unsigned Align = MBB->getAlignment()) EmitAlignment(Log2_32(Align)); - // If the block has its address taken, emit a special label to satisfy - // references to the block. This is done so that we don't need to - // remember the number of this label, and so that we can make - // forward references to labels without knowing what their numbers - // will be. + // If the block has its address taken, emit any labels that were used to + // reference the block. It is possible that there is more than one label + // here, because multiple LLVM BB's may have been RAUW'd to this block after + // the references were generated. if (MBB->hasAddressTaken()) { const BasicBlock *BB = MBB->getBasicBlock(); if (VerboseAsm) - OutStreamer.AddComment("Address Taken"); - OutStreamer.EmitLabel(GetBlockAddressSymbol(BB)); + OutStreamer.AddComment("Block address taken"); + + std::vector Syms = MMI->getAddrLabelSymbolToEmit(BB); + + for (unsigned i = 0, e = Syms.size(); i != e; ++i) + OutStreamer.EmitLabel(Syms[i]); } // Print the main label for the block. Modified: llvm/trunk/lib/CodeGen/MachineModuleInfo.cpp URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/CodeGen/MachineModuleInfo.cpp?rev=98595&r1=98594&r2=98595&view=diff ============================================================================== --- llvm/trunk/lib/CodeGen/MachineModuleInfo.cpp (original) +++ llvm/trunk/lib/CodeGen/MachineModuleInfo.cpp Mon Mar 15 19:29:39 2010 @@ -23,6 +23,7 @@ #include "llvm/Target/TargetMachine.h" #include "llvm/Target/TargetOptions.h" #include "llvm/MC/MCSymbol.h" +#include "llvm/ADT/PointerUnion.h" #include "llvm/Support/Dwarf.h" #include "llvm/Support/ErrorHandling.h" using namespace llvm; @@ -52,7 +53,10 @@ class MMIAddrLabelMap { MCContext &Context; struct AddrLabelSymEntry { - MCSymbol *Sym; // The symbol for the label. + /// Symbols - The symbols for the label. This is a pointer union that is + /// either one symbol (the common case) or a list of symbols. + PointerUnion*> Symbols; + Function *Fn; // The containing function of the BasicBlock. unsigned Index; // The index in BBCallbacks for the BasicBlock. }; @@ -75,9 +79,17 @@ ~MMIAddrLabelMap() { assert(DeletedAddrLabelsNeedingEmission.empty() && "Some labels for deleted blocks never got emitted"); + + // Deallocate any of the 'list of symbols' case. + for (DenseMap, AddrLabelSymEntry>::iterator + I = AddrLabelSymbols.begin(), E = AddrLabelSymbols.end(); I != E; ++I) + if (I->second.Symbols.is*>()) + delete I->second.Symbols.get*>(); } - MCSymbol *getAddrLabelSymbol(BasicBlock *BB); + MCSymbol *getAddrLabelSymbol(BasicBlock *BB); + std::vector getAddrLabelSymbolToEmit(BasicBlock *BB); + void takeDeletedSymbolsForFunction(Function *F, std::vector &Result); @@ -92,9 +104,11 @@ AddrLabelSymEntry &Entry = AddrLabelSymbols[BB]; // If we already had an entry for this block, just return it. - if (Entry.Sym) { + if (!Entry.Symbols.isNull()) { assert(BB->getParent() == Entry.Fn && "Parent changed"); - return Entry.Sym; + if (Entry.Symbols.is()) + return Entry.Symbols.get(); + return (*Entry.Symbols.get*>())[0]; } // Otherwise, this is a new entry, create a new symbol for it and add an @@ -103,9 +117,30 @@ BBCallbacks.back().setMap(this); Entry.Index = BBCallbacks.size()-1; Entry.Fn = BB->getParent(); - return Entry.Sym = Context.CreateTempSymbol(); + MCSymbol *Result = Context.CreateTempSymbol(); + Entry.Symbols = Result; + return Result; +} + +std::vector +MMIAddrLabelMap::getAddrLabelSymbolToEmit(BasicBlock *BB) { + assert(BB->hasAddressTaken() && + "Shouldn't get label for block without address taken"); + AddrLabelSymEntry &Entry = AddrLabelSymbols[BB]; + + std::vector Result; + + // If we already had an entry for this block, just return it. + if (Entry.Symbols.isNull()) + Result.push_back(getAddrLabelSymbol(BB)); + else if (MCSymbol *Sym = Entry.Symbols.dyn_cast()) + Result.push_back(Sym); + else + Result = *Entry.Symbols.get*>(); + return Result; } + /// takeDeletedSymbolsForFunction - If we have any deleted symbols for F, return /// them. void MMIAddrLabelMap:: @@ -128,36 +163,80 @@ // queue it up for later emission when the function is output. AddrLabelSymEntry Entry = AddrLabelSymbols[BB]; AddrLabelSymbols.erase(BB); - assert(Entry.Sym && "Didn't have a symbol, why a callback?"); + assert(!Entry.Symbols.isNull() && "Didn't have a symbol, why a callback?"); BBCallbacks[Entry.Index] = 0; // Clear the callback. - if (Entry.Sym->isDefined()) - return; - - // If the block is not yet defined, we need to emit it at the end of the - // function. Add the symbol to the DeletedAddrLabelsNeedingEmission list for - // the containing Function. Since the block is being deleted, its parent may - // already be removed, we have to get the function from 'Entry'. assert((BB->getParent() == 0 || BB->getParent() == Entry.Fn) && "Block/parent mismatch"); + + // Handle both the single and the multiple symbols cases. + if (MCSymbol *Sym = Entry.Symbols.dyn_cast()) { + if (Sym->isDefined()) + return; - DeletedAddrLabelsNeedingEmission[Entry.Fn].push_back(Entry.Sym); + // If the block is not yet defined, we need to emit it at the end of the + // function. Add the symbol to the DeletedAddrLabelsNeedingEmission list + // for the containing Function. Since the block is being deleted, its + // parent may already be removed, we have to get the function from 'Entry'. + DeletedAddrLabelsNeedingEmission[Entry.Fn].push_back(Sym); + } else { + std::vector *Syms = Entry.Symbols.get*>(); + + for (unsigned i = 0, e = Syms->size(); i != e; ++i) { + MCSymbol *Sym = (*Syms)[i]; + if (Sym->isDefined()) continue; // Ignore already emitted labels. + + // If the block is not yet defined, we need to emit it at the end of the + // function. Add the symbol to the DeletedAddrLabelsNeedingEmission list + // for the containing Function. Since the block is being deleted, its + // parent may already be removed, we have to get the function from + // 'Entry'. + DeletedAddrLabelsNeedingEmission[Entry.Fn].push_back(Sym); + } + + // The entry is deleted, free the memory associated with the symbol list. + delete Syms; + } } void MMIAddrLabelMap::UpdateForRAUWBlock(BasicBlock *Old, BasicBlock *New) { // Get the entry for the RAUW'd block and remove it from our map. AddrLabelSymEntry OldEntry = AddrLabelSymbols[Old]; AddrLabelSymbols.erase(Old); - assert(OldEntry.Sym && "Didn't have a symbol, why a callback?"); - + assert(!OldEntry.Symbols.isNull() && "Didn't have a symbol, why a callback?"); + + AddrLabelSymEntry &NewEntry = AddrLabelSymbols[New]; + // If New is not address taken, just move our symbol over to it. - if (!AddrLabelSymbols.count(New)) { + if (NewEntry.Symbols.isNull()) { BBCallbacks[OldEntry.Index] = New; // Update the callback. - AddrLabelSymbols[New] = OldEntry; // Set New's entry. - } else { - assert(0 && "Case not handled yet!"); - abort(); + NewEntry = OldEntry; // Set New's entry. + return; } + + BBCallbacks[OldEntry.Index] = 0; // Update the callback. + + // Otherwise, we need to add the old symbol to the new block's set. If it is + // just a single entry, upgrade it to a symbol list. + if (MCSymbol *PrevSym = NewEntry.Symbols.dyn_cast()) { + std::vector *SymList = new std::vector(); + SymList->push_back(PrevSym); + NewEntry.Symbols = SymList; + } + + std::vector *SymList = + NewEntry.Symbols.get*>(); + + // If the old entry was a single symbol, add it. + if (MCSymbol *Sym = OldEntry.Symbols.dyn_cast()) { + SymList->push_back(Sym); + return; + } + + // Otherwise, concatenate the list. + std::vector *Syms =OldEntry.Symbols.get*>(); + SymList->insert(SymList->end(), Syms->begin(), Syms->end()); + delete Syms; } @@ -260,6 +339,18 @@ return AddrLabelSymbols->getAddrLabelSymbol(const_cast(BB)); } +/// getAddrLabelSymbolToEmit - Return the symbol to be used for the specified +/// basic block when its address is taken. If other blocks were RAUW'd to +/// this one, we may have to emit them as well, return the whole set. +std::vector MachineModuleInfo:: +getAddrLabelSymbolToEmit(const BasicBlock *BB) { + // Lazily create AddrLabelSymbols. + if (AddrLabelSymbols == 0) + AddrLabelSymbols = new MMIAddrLabelMap(Context); + return AddrLabelSymbols->getAddrLabelSymbolToEmit(const_cast(BB)); +} + + /// takeDeletedSymbolsForFunction - If the specified function has had any /// references to address-taken blocks generated, but the block got deleted, /// return the symbol now so we can emit it. This prevents emitting a Modified: llvm/trunk/test/CodeGen/Generic/addr-label.ll URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/CodeGen/Generic/addr-label.ll?rev=98595&r1=98594&r2=98595&view=diff ============================================================================== --- llvm/trunk/test/CodeGen/Generic/addr-label.ll (original) +++ llvm/trunk/test/CodeGen/Generic/addr-label.ll Mon Mar 15 19:29:39 2010 @@ -37,3 +37,22 @@ ret: ret i32 -1 } + +; Issues with a BB that gets RAUW'd to another one after references are +; generated. +define void @test3(i8** %P, i8** %Q) nounwind { +entry: + store i8* blockaddress(@test3b, %test_label), i8** %P + store i8* blockaddress(@test3b, %ret), i8** %Q + ret void +} + +define i32 @test3b() nounwind { +entry: + br label %test_label +test_label: + br label %ret +ret: + ret i32 -1 +} + From daniel at zuster.org Mon Mar 15 19:31:40 2010 From: daniel at zuster.org (Daniel Dunbar) Date: Mon, 15 Mar 2010 17:31:40 -0700 Subject: [llvm-commits] Extract MachObjectWriter class to own header and code files In-Reply-To: <9719867c1003151006r720d53cewebc80de9802ed238@mail.gmail.com> References: <9719867c1003151006r720d53cewebc80de9802ed238@mail.gmail.com> Message-ID: <6a8523d61003151731v66234328qd84112c1d364a8a7@mail.gmail.com> Hi Aaron, This has been on my list, but for the time being I find it convenient to have all the code in the same place. I also want to factor out a few more minor things before splitting in the target independent assembler and the object file writer. Is this blocking work you are hoping to do? - Daniel On Mon, Mar 15, 2010 at 10:06 AM, Aaron Gray wrote: > Hi, > This patch extracts 'class MachObjectWriter' into its own .h and .cpp > files. > Tested on MSVC and Cygwin. > Aaron > > _______________________________________________ > llvm-commits mailing list > llvm-commits at cs.uiuc.edu > http://lists.cs.uiuc.edu/mailman/listinfo/llvm-commits > > From bob.wilson at apple.com Mon Mar 15 19:31:16 2010 From: bob.wilson at apple.com (Bob Wilson) Date: Tue, 16 Mar 2010 00:31:16 -0000 Subject: [llvm-commits] [llvm] r98596 - /llvm/trunk/lib/Target/ARM/ARMLoadStoreOptimizer.cpp Message-ID: <20100316003116.17CC82A6C12C@llvm.org> Author: bwilson Date: Mon Mar 15 19:31:15 2010 New Revision: 98596 URL: http://llvm.org/viewvc/llvm-project?rev=98596&view=rev Log: Wrap a long line and add some parens to be consistent. Modified: llvm/trunk/lib/Target/ARM/ARMLoadStoreOptimizer.cpp Modified: llvm/trunk/lib/Target/ARM/ARMLoadStoreOptimizer.cpp URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Target/ARM/ARMLoadStoreOptimizer.cpp?rev=98596&r1=98595&r2=98596&view=diff ============================================================================== --- llvm/trunk/lib/Target/ARM/ARMLoadStoreOptimizer.cpp (original) +++ llvm/trunk/lib/Target/ARM/ARMLoadStoreOptimizer.cpp Mon Mar 15 19:31:15 2010 @@ -243,8 +243,9 @@ BaseKill = true; // New base is always killed right its use. } - bool isDPR = Opcode == ARM::VLDRD || Opcode == ARM::VSTRD; - bool isDef = isi32Load(Opcode) || Opcode == ARM::VLDRS || Opcode == ARM::VLDRD; + bool isDPR = (Opcode == ARM::VLDRD || Opcode == ARM::VSTRD); + bool isDef = (isi32Load(Opcode) || Opcode == ARM::VLDRS || + Opcode == ARM::VLDRD); Opcode = getLoadStoreMultipleOpcode(Opcode); MachineInstrBuilder MIB = (isAM4) ? BuildMI(MBB, MBBI, dl, TII->get(Opcode)) From sabre at nondot.org Mon Mar 15 19:35:11 2010 From: sabre at nondot.org (Chris Lattner) Date: Tue, 16 Mar 2010 00:35:11 -0000 Subject: [llvm-commits] [llvm] r98597 - /llvm/trunk/utils/TableGen/DAGISelMatcherOpt.cpp Message-ID: <20100316003511.344952A6C12C@llvm.org> Author: lattner Date: Mon Mar 15 19:35:11 2010 New Revision: 98597 URL: http://llvm.org/viewvc/llvm-project?rev=98597&view=rev Log: don't form a RecordChild or CheckChildType for child #'s over 7, we don't have enums for them. Modified: llvm/trunk/utils/TableGen/DAGISelMatcherOpt.cpp Modified: llvm/trunk/utils/TableGen/DAGISelMatcherOpt.cpp URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/utils/TableGen/DAGISelMatcherOpt.cpp?rev=98597&r1=98596&r2=98597&view=diff ============================================================================== --- llvm/trunk/utils/TableGen/DAGISelMatcherOpt.cpp (original) +++ llvm/trunk/utils/TableGen/DAGISelMatcherOpt.cpp Mon Mar 15 19:35:11 2010 @@ -44,11 +44,13 @@ if (MoveChildMatcher *MC = dyn_cast(N)) { Matcher *New = 0; if (RecordMatcher *RM = dyn_cast(MC->getNext())) - New = new RecordChildMatcher(MC->getChildNo(), RM->getWhatFor(), - RM->getResultNo()); + if (MC->getChildNo() < 8) // Only have RecordChild0...7 + New = new RecordChildMatcher(MC->getChildNo(), RM->getWhatFor(), + RM->getResultNo()); if (CheckTypeMatcher *CT= dyn_cast(MC->getNext())) - New = new CheckChildTypeMatcher(MC->getChildNo(), CT->getType()); + if (MC->getChildNo() < 8) // Only have CheckChildType0...7 + New = new CheckChildTypeMatcher(MC->getChildNo(), CT->getType()); if (New) { // Insert the new node. From aaronngray.lists at googlemail.com Mon Mar 15 20:01:22 2010 From: aaronngray.lists at googlemail.com (Aaron Gray) Date: Tue, 16 Mar 2010 01:01:22 +0000 Subject: [llvm-commits] Extract MachObjectWriter class to own header and code files In-Reply-To: <6a8523d61003151731v66234328qd84112c1d364a8a7@mail.gmail.com> References: <9719867c1003151006r720d53cewebc80de9802ed238@mail.gmail.com> <6a8523d61003151731v66234328qd84112c1d364a8a7@mail.gmail.com> Message-ID: <9719867c1003151801u5f4f4de2t1403eacc5eddf2b9@mail.gmail.com> On 16 March 2010 00:31, Daniel Dunbar wrote: > Hi Aaron, > > This has been on my list, but for the time being I find it convenient > to have all the code in the same place. I also want to factor out a > few more minor things before splitting in the target independent > assembler and the object file writer. > > Is this blocking work you are hoping to do? > Hi Daniel, It would be good to get to the stage where I can work on the COFFWriter and COFFStreamer. Basically I can wait but I thought a few file and class wise normalizations would not go a miss :) Also I wanted to introduce a common ObjectWriter abstract class for MachObjectWriter, ELFObjectWriter, and COFFWriter, with Write and virtual WriteObject methods. I had worked on the older COFFWriter and got that nearly working with LLVM-GCC so would like to get back to where I was progress wise. Hope not to rock the boat :) Aaron > On Mon, Mar 15, 2010 at 10:06 AM, Aaron Gray > wrote: > > Hi, > > This patch extracts 'class MachObjectWriter' into its own .h and .cpp > > files. > > Tested on MSVC and Cygwin. > > Aaron > > > > _______________________________________________ > > llvm-commits mailing list > > llvm-commits at cs.uiuc.edu > > http://lists.cs.uiuc.edu/mailman/listinfo/llvm-commits > > > > > -------------- next part -------------- An HTML attachment was scrubbed... URL: http://lists.cs.uiuc.edu/pipermail/llvm-commits/attachments/20100316/c79a9cd2/attachment.html From isanbard at gmail.com Mon Mar 15 20:05:35 2010 From: isanbard at gmail.com (Bill Wendling) Date: Tue, 16 Mar 2010 01:05:35 -0000 Subject: [llvm-commits] [llvm] r98599 - /llvm/trunk/lib/CodeGen/RegAllocLocal.cpp Message-ID: <20100316010535.930582A6C12C@llvm.org> Author: void Date: Mon Mar 15 20:05:35 2010 New Revision: 98599 URL: http://llvm.org/viewvc/llvm-project?rev=98599&view=rev Log: When checking if something's killed, don't rely simply on whether it's marked as "used outside of the block". If the block ends in a return, then it won't be used outside of it. Modified: llvm/trunk/lib/CodeGen/RegAllocLocal.cpp Modified: llvm/trunk/lib/CodeGen/RegAllocLocal.cpp URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/CodeGen/RegAllocLocal.cpp?rev=98599&r1=98598&r2=98599&view=diff ============================================================================== --- llvm/trunk/lib/CodeGen/RegAllocLocal.cpp (original) +++ llvm/trunk/lib/CodeGen/RegAllocLocal.cpp Mon Mar 15 20:05:35 2010 @@ -671,7 +671,8 @@ // Live-out (of the function) registers contain return values of the function, // so we need to make sure they are alive at return time. - if (!MBB.empty() && MBB.back().getDesc().isReturn()) { + bool BBEndsInReturn = !MBB.empty() && MBB.back().getDesc().isReturn(); + if (BBEndsInReturn) { MachineInstr* Ret = &MBB.back(); for (MachineRegisterInfo::liveout_iterator I = MF->getRegInfo().liveout_begin(), @@ -696,7 +697,10 @@ bool usedOutsideBlock = isPhysReg ? false : UsedInMultipleBlocks.test(MO.getReg() - TargetRegisterInfo::FirstVirtualRegister); - if (!isPhysReg && !usedOutsideBlock) { + + // If the machine BB ends in a return instruction, then the value isn't used + // outside of the BB. + if (!isPhysReg && (!usedOutsideBlock || BBEndsInReturn)) { // DBG_VALUE complicates this: if the only refs of a register outside // this block are DBG_VALUE, we can't keep the reg live just for that, // as it will cause the reg to be spilled at the end of this block when @@ -704,7 +708,7 @@ // happens. bool UsedByDebugValueOnly = false; for (MachineRegisterInfo::reg_iterator UI = MRI.reg_begin(MO.getReg()), - UE = MRI.reg_end(); UI != UE; ++UI) + UE = MRI.reg_end(); UI != UE; ++UI) { // Two cases: // - used in another block // - used in the same block before it is defined (loop) @@ -714,6 +718,7 @@ UsedByDebugValueOnly = true; continue; } + // A non-DBG_VALUE use means we can leave DBG_VALUE uses alone. UsedInMultipleBlocks.set(MO.getReg() - TargetRegisterInfo::FirstVirtualRegister); @@ -721,6 +726,8 @@ UsedByDebugValueOnly = false; break; } + } + if (UsedByDebugValueOnly) for (MachineRegisterInfo::reg_iterator UI = MRI.reg_begin(MO.getReg()), UE = MRI.reg_end(); UI != UE; ++UI) @@ -730,16 +737,16 @@ UI.getOperand().setReg(0U); } - // Physical registers and those that are not live-out of the block - // are killed/dead at their last use/def within this block. - if (isPhysReg || !usedOutsideBlock) { + // Physical registers and those that are not live-out of the block are + // killed/dead at their last use/def within this block. + if (isPhysReg || !usedOutsideBlock || BBEndsInReturn) if (MO.isUse()) { // Don't mark uses that are tied to defs as kills. if (!MI->isRegTiedToDefOperand(idx)) MO.setIsKill(true); - } else + } else { MO.setIsDead(true); - } + } } } From evan.cheng at apple.com Mon Mar 15 20:17:37 2010 From: evan.cheng at apple.com (Evan Cheng) Date: Mon, 15 Mar 2010 18:17:37 -0700 Subject: [llvm-commits] [llvm] r98599 - /llvm/trunk/lib/CodeGen/RegAllocLocal.cpp In-Reply-To: <20100316010535.930582A6C12C@llvm.org> References: <20100316010535.930582A6C12C@llvm.org> Message-ID: <27A26DBF-247B-4686-BDCC-91612A94B35D@apple.com> On Mar 15, 2010, at 6:05 PM, Bill Wendling wrote: > Author: void > Date: Mon Mar 15 20:05:35 2010 > New Revision: 98599 > > URL: http://llvm.org/viewvc/llvm-project?rev=98599&view=rev > Log: > When checking if something's killed, don't rely simply on whether it's marked as > "used outside of the block". If the block ends in a return, then it won't be > used outside of it. > > Modified: > llvm/trunk/lib/CodeGen/RegAllocLocal.cpp > > Modified: llvm/trunk/lib/CodeGen/RegAllocLocal.cpp > URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/CodeGen/RegAllocLocal.cpp?rev=98599&r1=98598&r2=98599&view=diff > ============================================================================== > --- llvm/trunk/lib/CodeGen/RegAllocLocal.cpp (original) > +++ llvm/trunk/lib/CodeGen/RegAllocLocal.cpp Mon Mar 15 20:05:35 2010 > @@ -671,7 +671,8 @@ > > // Live-out (of the function) registers contain return values of the function, > // so we need to make sure they are alive at return time. > - if (!MBB.empty() && MBB.back().getDesc().isReturn()) { > + bool BBEndsInReturn = !MBB.empty() && MBB.back().getDesc().isReturn(); I think it should use getFirstTerminator() instead. Evan > + if (BBEndsInReturn) { > MachineInstr* Ret = &MBB.back(); > for (MachineRegisterInfo::liveout_iterator > I = MF->getRegInfo().liveout_begin(), > @@ -696,7 +697,10 @@ > bool usedOutsideBlock = isPhysReg ? false : > UsedInMultipleBlocks.test(MO.getReg() - > TargetRegisterInfo::FirstVirtualRegister); > - if (!isPhysReg && !usedOutsideBlock) { > + > + // If the machine BB ends in a return instruction, then the value isn't used > + // outside of the BB. > + if (!isPhysReg && (!usedOutsideBlock || BBEndsInReturn)) { > // DBG_VALUE complicates this: if the only refs of a register outside > // this block are DBG_VALUE, we can't keep the reg live just for that, > // as it will cause the reg to be spilled at the end of this block when > @@ -704,7 +708,7 @@ > // happens. > bool UsedByDebugValueOnly = false; > for (MachineRegisterInfo::reg_iterator UI = MRI.reg_begin(MO.getReg()), > - UE = MRI.reg_end(); UI != UE; ++UI) > + UE = MRI.reg_end(); UI != UE; ++UI) { > // Two cases: > // - used in another block > // - used in the same block before it is defined (loop) > @@ -714,6 +718,7 @@ > UsedByDebugValueOnly = true; > continue; > } > + > // A non-DBG_VALUE use means we can leave DBG_VALUE uses alone. > UsedInMultipleBlocks.set(MO.getReg() - > TargetRegisterInfo::FirstVirtualRegister); > @@ -721,6 +726,8 @@ > UsedByDebugValueOnly = false; > break; > } > + } > + > if (UsedByDebugValueOnly) > for (MachineRegisterInfo::reg_iterator UI = MRI.reg_begin(MO.getReg()), > UE = MRI.reg_end(); UI != UE; ++UI) > @@ -730,16 +737,16 @@ > UI.getOperand().setReg(0U); > } > > - // Physical registers and those that are not live-out of the block > - // are killed/dead at their last use/def within this block. > - if (isPhysReg || !usedOutsideBlock) { > + // Physical registers and those that are not live-out of the block are > + // killed/dead at their last use/def within this block. > + if (isPhysReg || !usedOutsideBlock || BBEndsInReturn) > if (MO.isUse()) { > // Don't mark uses that are tied to defs as kills. > if (!MI->isRegTiedToDefOperand(idx)) > MO.setIsKill(true); > - } else > + } else { > MO.setIsDead(true); > - } > + } > } > } > > > > _______________________________________________ > llvm-commits mailing list > llvm-commits at cs.uiuc.edu > http://lists.cs.uiuc.edu/mailman/listinfo/llvm-commits From isanbard at gmail.com Mon Mar 15 20:54:21 2010 From: isanbard at gmail.com (Bill Wendling) Date: Tue, 16 Mar 2010 01:54:21 -0000 Subject: [llvm-commits] [llvm] r98602 - /llvm/trunk/test/CodeGen/X86/liveness-local-regalloc.ll Message-ID: <20100316015421.0A9192A6C12C@llvm.org> Author: void Date: Mon Mar 15 20:54:20 2010 New Revision: 98602 URL: http://llvm.org/viewvc/llvm-project?rev=98602&view=rev Log: Forgot testcase for r98599. Added: llvm/trunk/test/CodeGen/X86/liveness-local-regalloc.ll Added: llvm/trunk/test/CodeGen/X86/liveness-local-regalloc.ll URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/CodeGen/X86/liveness-local-regalloc.ll?rev=98602&view=auto ============================================================================== --- llvm/trunk/test/CodeGen/X86/liveness-local-regalloc.ll (added) +++ llvm/trunk/test/CodeGen/X86/liveness-local-regalloc.ll Mon Mar 15 20:54:20 2010 @@ -0,0 +1,60 @@ +; RUN: llc < %s -O3 -regalloc=local -mtriple=x86_64-apple-darwin10 +; + +%0 = type { i32, i8*, i8*, %1*, i8*, i64, i64, i32, i32, i32, i32, [1024 x i8] } +%1 = type { i8*, i32, i32, i16, i16, %2, i32, i8*, i32 (i8*)*, i32 (i8*, i8*, i32)*, i64 (i8*, i64, i32)*, i32 (i8*, i8*, i32)*, %2, %3*, i32, [3 x i8], [1 x i8], %2, i32, i64 } +%2 = type { i8*, i32 } +%3 = type opaque + +declare fastcc i32 @func(%0*, i32, i32) nounwind ssp + +define fastcc void @func2(%0* %arg, i32 %arg1) nounwind ssp { +bb: + br label %.exit3 + +.exit3: ; preds = %.exit3, %bb + switch i32 undef, label %.exit3 [ + i32 -1, label %.loopexit + i32 37, label %bb2 + ] + +bb2: ; preds = %bb5, %bb3, %.exit3 + br i1 undef, label %bb3, label %bb5 + +bb3: ; preds = %bb2 + switch i32 undef, label %infloop [ + i32 125, label %.loopexit + i32 -1, label %bb4 + i32 37, label %bb2 + ] + +bb4: ; preds = %bb3 + %tmp = add nsw i32 undef, 1 ; [#uses=1] + br label %.loopexit + +bb5: ; preds = %bb2 + switch i32 undef, label %infloop1 [ + i32 -1, label %.loopexit + i32 37, label %bb2 + ] + +.loopexit: ; preds = %bb5, %bb4, %bb3, %.exit3 + %.04 = phi i32 [ %tmp, %bb4 ], [ undef, %bb3 ], [ undef, %.exit3 ], [ undef, %bb5 ] ; [#uses=2] + br i1 undef, label %bb8, label %bb6 + +bb6: ; preds = %.loopexit + %tmp7 = tail call fastcc i32 @func(%0* %arg, i32 %.04, i32 undef) nounwind ssp ; [#uses=0] + ret void + +bb8: ; preds = %.loopexit + %tmp9 = sext i32 %.04 to i64 ; [#uses=1] + %tmp10 = getelementptr inbounds %0* %arg, i64 0, i32 11, i64 %tmp9 ; [#uses=1] + store i8 0, i8* %tmp10, align 1 + ret void + +infloop: ; preds = %infloop, %bb3 + br label %infloop + +infloop1: ; preds = %infloop1, %bb5 + br label %infloop1 +} From isanbard at gmail.com Mon Mar 15 21:01:52 2010 From: isanbard at gmail.com (Bill Wendling) Date: Tue, 16 Mar 2010 02:01:52 -0000 Subject: [llvm-commits] [llvm] r98604 - /llvm/trunk/lib/CodeGen/RegAllocLocal.cpp Message-ID: <20100316020152.204F82A6C12C@llvm.org> Author: void Date: Mon Mar 15 21:01:51 2010 New Revision: 98604 URL: http://llvm.org/viewvc/llvm-project?rev=98604&view=rev Log: Use getFirstTerminator(). Modified: llvm/trunk/lib/CodeGen/RegAllocLocal.cpp Modified: llvm/trunk/lib/CodeGen/RegAllocLocal.cpp URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/CodeGen/RegAllocLocal.cpp?rev=98604&r1=98603&r2=98604&view=diff ============================================================================== --- llvm/trunk/lib/CodeGen/RegAllocLocal.cpp (original) +++ llvm/trunk/lib/CodeGen/RegAllocLocal.cpp Mon Mar 15 21:01:51 2010 @@ -671,9 +671,10 @@ // Live-out (of the function) registers contain return values of the function, // so we need to make sure they are alive at return time. - bool BBEndsInReturn = !MBB.empty() && MBB.back().getDesc().isReturn(); - if (BBEndsInReturn) { - MachineInstr* Ret = &MBB.back(); + MachineBasicBlock::iterator Ret = MBB.getFirstTerminator(); + bool BBEndsInReturn = (Ret != MBB.end() && Ret->getDesc().isReturn()); + + if (BBEndsInReturn) for (MachineRegisterInfo::liveout_iterator I = MF->getRegInfo().liveout_begin(), E = MF->getRegInfo().liveout_end(); I != E; ++I) @@ -681,7 +682,6 @@ Ret->addOperand(MachineOperand::CreateReg(*I, false, true)); LastUseDef[*I] = std::make_pair(Ret, Ret->getNumOperands()-1); } - } // Finally, loop over the final use/def of each reg // in the block and determine if it is dead. From wendling at apple.com Mon Mar 15 23:39:09 2010 From: wendling at apple.com (Bill Wendling) Date: Mon, 15 Mar 2010 21:39:09 -0700 Subject: [llvm-commits] [llvm] r98495 - in /llvm/trunk: include/llvm/CodeGen/AsmPrinter.h include/llvm/CodeGen/MachineModuleInfo.h lib/CodeGen/AsmPrinter/AsmPrinter.cpp lib/CodeGen/MachineModuleInfo.cpp lib/CodeGen/SelectionDAG/SelectionDAGISel.cpp test/CodeGen/ARM/indirectbr.ll test/CodeGen/PowerPC/indirectbr.ll test/CodeGen/XCore/indirectbr.ll In-Reply-To: <20100314175323.4C1FD2A6C12C@llvm.org> References: <20100314175323.4C1FD2A6C12C@llvm.org> Message-ID: <683E81E1-16F8-40DF-8F1B-27FFBDC681CF@apple.com> Yes! Thanks. :-) -bw On Mar 14, 2010, at 10:53 AM, Chris Lattner wrote: > Author: lattner > Date: Sun Mar 14 12:53:23 2010 > New Revision: 98495 > > URL: http://llvm.org/viewvc/llvm-project?rev=98495&view=rev > Log: > fix AsmPrinter::GetBlockAddressSymbol to always return a unique > label instead of trying to form one based on the BB name (which > causes collisions if the name is empty). This fixes PR6608 > > Modified: > llvm/trunk/include/llvm/CodeGen/AsmPrinter.h > llvm/trunk/include/llvm/CodeGen/MachineModuleInfo.h > llvm/trunk/lib/CodeGen/AsmPrinter/AsmPrinter.cpp > llvm/trunk/lib/CodeGen/MachineModuleInfo.cpp > llvm/trunk/lib/CodeGen/SelectionDAG/SelectionDAGISel.cpp > llvm/trunk/test/CodeGen/ARM/indirectbr.ll > llvm/trunk/test/CodeGen/PowerPC/indirectbr.ll > llvm/trunk/test/CodeGen/XCore/indirectbr.ll > > Modified: llvm/trunk/include/llvm/CodeGen/AsmPrinter.h > URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/CodeGen/AsmPrinter.h?rev=98495&r1=98494&r2=98495&view=diff > ============================================================================== > --- llvm/trunk/include/llvm/CodeGen/AsmPrinter.h (original) > +++ llvm/trunk/include/llvm/CodeGen/AsmPrinter.h Sun Mar 14 12:53:23 2010 > @@ -337,8 +337,7 @@ > /// GetBlockAddressSymbol - Return the MCSymbol used to satisfy BlockAddress > /// uses of the specified basic block. > MCSymbol *GetBlockAddressSymbol(const BlockAddress *BA) const; > - MCSymbol *GetBlockAddressSymbol(const Function *F, > - const BasicBlock *BB) const; > + MCSymbol *GetBlockAddressSymbol(const BasicBlock *BB) const; > > /// EmitBasicBlockStart - This method prints the label for the specified > /// MachineBasicBlock, an alignment (if present) and a comment describing > > Modified: llvm/trunk/include/llvm/CodeGen/MachineModuleInfo.h > URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/CodeGen/MachineModuleInfo.h?rev=98495&r1=98494&r2=98495&view=diff > ============================================================================== > --- llvm/trunk/include/llvm/CodeGen/MachineModuleInfo.h (original) > +++ llvm/trunk/include/llvm/CodeGen/MachineModuleInfo.h Sun Mar 14 12:53:23 2010 > @@ -139,6 +139,11 @@ > /// llvm.compiler.used. > SmallPtrSet UsedFunctions; > > + > + /// AddrLabelSymbols - This map keeps track of which symbol is being used for > + /// the specified basic block's address of label. > + DenseMap, MCSymbol*> AddrLabelSymbols; > + > bool CallsEHReturn; > bool CallsUnwindInit; > > @@ -203,6 +208,11 @@ > /// handling comsumers. > std::vector &getFrameMoves() { return FrameMoves; } > > + /// getAddrLabelSymbol - Return the symbol to be used for the specified basic > + /// block when its address is taken. This cannot be its normal LBB label > + /// because the block may be accessed outside its containing function. > + MCSymbol *getAddrLabelSymbol(const BasicBlock *BB); > + > //===- EH ---------------------------------------------------------------===// > > /// getOrCreateLandingPadInfo - Find or create an LandingPadInfo for the > > Modified: llvm/trunk/lib/CodeGen/AsmPrinter/AsmPrinter.cpp > URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/CodeGen/AsmPrinter/AsmPrinter.cpp?rev=98495&r1=98494&r2=98495&view=diff > ============================================================================== > --- llvm/trunk/lib/CodeGen/AsmPrinter/AsmPrinter.cpp (original) > +++ llvm/trunk/lib/CodeGen/AsmPrinter/AsmPrinter.cpp Sun Mar 14 12:53:23 2010 > @@ -1580,28 +1580,11 @@ > } > > MCSymbol *AsmPrinter::GetBlockAddressSymbol(const BlockAddress *BA) const { > - return GetBlockAddressSymbol(BA->getFunction(), BA->getBasicBlock()); > + return MMI->getAddrLabelSymbol(BA->getBasicBlock()); > } > > -MCSymbol *AsmPrinter::GetBlockAddressSymbol(const Function *F, > - const BasicBlock *BB) const { > - assert(BB->hasName() && > - "Address of anonymous basic block not supported yet!"); > - > - // This code must use the function name itself, and not the function number, > - // since it must be possible to generate the label name from within other > - // functions. > - SmallString<60> FnName; > - Mang->getNameWithPrefix(FnName, F, false); > - > - // FIXME: THIS IS BROKEN IF THE LLVM BASIC BLOCK DOESN'T HAVE A NAME! > - SmallString<60> NameResult; > - Mang->getNameWithPrefix(NameResult, > - StringRef("BA") + Twine((unsigned)FnName.size()) + > - "_" + FnName.str() + "_" + BB->getName(), > - Mangler::Private); > - > - return OutContext.GetOrCreateTemporarySymbol(NameResult.str()); > +MCSymbol *AsmPrinter::GetBlockAddressSymbol(const BasicBlock *BB) const { > + return MMI->getAddrLabelSymbol(BB); > } > > /// GetCPISymbol - Return the symbol for the specified constant pool entry. > @@ -1730,7 +1713,7 @@ > const BasicBlock *BB = MBB->getBasicBlock(); > if (VerboseAsm) > OutStreamer.AddComment("Address Taken"); > - OutStreamer.EmitLabel(GetBlockAddressSymbol(BB->getParent(), BB)); > + OutStreamer.EmitLabel(GetBlockAddressSymbol(BB)); > } > > // Print the main label for the block. > > Modified: llvm/trunk/lib/CodeGen/MachineModuleInfo.cpp > URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/CodeGen/MachineModuleInfo.cpp?rev=98495&r1=98494&r2=98495&view=diff > ============================================================================== > --- llvm/trunk/lib/CodeGen/MachineModuleInfo.cpp (original) > +++ llvm/trunk/lib/CodeGen/MachineModuleInfo.cpp Sun Mar 14 12:53:23 2010 > @@ -104,6 +104,18 @@ > UsedFunctions.insert(F); > } > > +/// getAddrLabelSymbol - Return the symbol to be used for the specified basic > +/// block when its address is taken. This cannot be its normal LBB label > +/// because the block may be accessed outside its containing function. > +MCSymbol *MachineModuleInfo::getAddrLabelSymbol(const BasicBlock *BB) { > + assert(BB->hasAddressTaken() && > + "Shouldn't get label for block without address taken"); > + MCSymbol *&Entry = AddrLabelSymbols[const_cast(BB)]; > + if (Entry) return Entry; > + return Entry = Context.CreateTempSymbol(); > +} > + > + > //===-EH-------------------------------------------------------------------===// > > /// getOrCreateLandingPadInfo - Find or create an LandingPadInfo for the > > Modified: llvm/trunk/lib/CodeGen/SelectionDAG/SelectionDAGISel.cpp > URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/CodeGen/SelectionDAG/SelectionDAGISel.cpp?rev=98495&r1=98494&r2=98495&view=diff > ============================================================================== > --- llvm/trunk/lib/CodeGen/SelectionDAG/SelectionDAGISel.cpp (original) > +++ llvm/trunk/lib/CodeGen/SelectionDAG/SelectionDAGISel.cpp Sun Mar 14 12:53:23 2010 > @@ -2035,6 +2035,8 @@ > case ISD::EntryToken: // These nodes remain the same. > case ISD::BasicBlock: > case ISD::Register: > + //case ISD::VALUETYPE: > + //case ISD::CONDCODE: > case ISD::HANDLENODE: > case ISD::TargetConstant: > case ISD::TargetConstantFP: > > Modified: llvm/trunk/test/CodeGen/ARM/indirectbr.ll > URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/CodeGen/ARM/indirectbr.ll?rev=98495&r1=98494&r2=98495&view=diff > ============================================================================== > --- llvm/trunk/test/CodeGen/ARM/indirectbr.ll (original) > +++ llvm/trunk/test/CodeGen/ARM/indirectbr.ll Sun Mar 14 12:53:23 2010 > @@ -59,6 +59,6 @@ > store i8* blockaddress(@foo, %L5), i8** @nextaddr, align 4 > ret i32 %res.3 > } > -; ARM: .long L_BA4__foo_L5-(LPC{{.*}}+8) > -; THUMB: .long L_BA4__foo_L5-(LPC{{.*}}+4) > -; THUMB2: .long L_BA4__foo_L5 > +; ARM: .long Ltmp0-(LPC{{.*}}+8) > +; THUMB: .long Ltmp0-(LPC{{.*}}+4) > +; THUMB2: .long Ltmp0 > > Modified: llvm/trunk/test/CodeGen/PowerPC/indirectbr.ll > URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/CodeGen/PowerPC/indirectbr.ll?rev=98495&r1=98494&r2=98495&view=diff > ============================================================================== > --- llvm/trunk/test/CodeGen/PowerPC/indirectbr.ll (original) > +++ llvm/trunk/test/CodeGen/PowerPC/indirectbr.ll Sun Mar 14 12:53:23 2010 > @@ -43,12 +43,12 @@ > > L1: ; preds = %L2, %bb2 > %res.3 = phi i32 [ %phitmp, %L2 ], [ 2, %bb2 ] ; [#uses=1] > -; PIC: addis r4, r4, ha16(L_BA4__foo_L5-"L1$pb") > -; PIC: li r6, lo16(L_BA4__foo_L5-"L1$pb") > +; PIC: addis r4, r4, ha16(Ltmp0-"L1$pb") > +; PIC: li r6, lo16(Ltmp0-"L1$pb") > ; PIC: add r4, r4, r6 > ; PIC: stw r4 > -; STATIC: li r5, lo16(L_BA4__foo_L5) > -; STATIC: addis r5, r5, ha16(L_BA4__foo_L5) > +; STATIC: li r5, lo16(Ltmp0) > +; STATIC: addis r5, r5, ha16(Ltmp0) > ; STATIC: stw r5 > store i8* blockaddress(@foo, %L5), i8** @nextaddr, align 4 > ret i32 %res.3 > > Modified: llvm/trunk/test/CodeGen/XCore/indirectbr.ll > URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/CodeGen/XCore/indirectbr.ll?rev=98495&r1=98494&r2=98495&view=diff > ============================================================================== > --- llvm/trunk/test/CodeGen/XCore/indirectbr.ll (original) > +++ llvm/trunk/test/CodeGen/XCore/indirectbr.ll Sun Mar 14 12:53:23 2010 > @@ -38,7 +38,7 @@ > > L1: ; preds = %L2, %bb2 > %res.3 = phi i32 [ %phitmp, %L2 ], [ 2, %bb2 ] ; [#uses=1] > -; CHECK: ldap r11, .LBA3_foo_L5 > +; CHECK: ldap r11, .Ltmp0 > ; CHECK: stw r11, dp[nextaddr] > store i8* blockaddress(@foo, %L5), i8** @nextaddr, align 4 > ret i32 %res.3 > > > _______________________________________________ > llvm-commits mailing list > llvm-commits at cs.uiuc.edu > http://lists.cs.uiuc.edu/mailman/listinfo/llvm-commits From bob.wilson at apple.com Tue Mar 16 00:33:29 2010 From: bob.wilson at apple.com (Bob Wilson) Date: Tue, 16 Mar 2010 05:33:29 -0000 Subject: [llvm-commits] [llvm] r98610 - /llvm/trunk/test/CodeGen/Thumb2/2010-03-15-AsmCCClobber.ll Message-ID: <20100316053329.BF0B62A6C12C@llvm.org> Author: bwilson Date: Tue Mar 16 00:33:29 2010 New Revision: 98610 URL: http://llvm.org/viewvc/llvm-project?rev=98610&view=rev Log: Add a testcase for the change in r98586. Added: llvm/trunk/test/CodeGen/Thumb2/2010-03-15-AsmCCClobber.ll Added: llvm/trunk/test/CodeGen/Thumb2/2010-03-15-AsmCCClobber.ll URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/CodeGen/Thumb2/2010-03-15-AsmCCClobber.ll?rev=98610&view=auto ============================================================================== --- llvm/trunk/test/CodeGen/Thumb2/2010-03-15-AsmCCClobber.ll (added) +++ llvm/trunk/test/CodeGen/Thumb2/2010-03-15-AsmCCClobber.ll Tue Mar 16 00:33:29 2010 @@ -0,0 +1,63 @@ +; RUN: llc < %s -mtriple=thumbv7-apple-darwin -mcpu=cortex-a8 | FileCheck %s +; Radar 7459078 +target datalayout = "e-p:32:32:32-i1:8:32-i8:8:32-i16:16:32-i32:32:32-i64:32:32-f32:32:32-f64:32:32-v64:64:64-v128:128:128-a0:0:32-n32" + +%0 = type { i32, i32 } +%s1 = type { %s3, i32, %s4, i8*, void (i8*, i8*)*, i8*, i32*, i32*, i32*, i32, i64, [1 x i32] } +%s2 = type { i32 (...)**, %s4 } +%s3 = type { %s2, i32, i32, i32*, [4 x i8], float, %s4, i8*, i8* } +%s4 = type { %s5 } +%s5 = type { i32 } + +; Make sure the cmp is not scheduled before the InlineAsm that clobbers cc. +; CHECK: InlineAsm End +; CHECK: cmp +; CHECK: beq +define arm_apcscc void @test(%s1* %this, i32 %format, i32 %w, i32 %h, i32 %levels, i32* %s, i8* %data, i32* nocapture %rowbytes, void (i8*, i8*)* %release, i8* %info) nounwind { +entry: + %tmp1 = getelementptr inbounds %s1* %this, i32 0, i32 0, i32 0, i32 1, i32 0, i32 0 + volatile store i32 1, i32* %tmp1, align 4 + %tmp12 = getelementptr inbounds %s1* %this, i32 0, i32 1 + store i32 %levels, i32* %tmp12, align 4 + %tmp13 = getelementptr inbounds %s1* %this, i32 0, i32 3 + store i8* %data, i8** %tmp13, align 4 + %tmp14 = getelementptr inbounds %s1* %this, i32 0, i32 4 + store void (i8*, i8*)* %release, void (i8*, i8*)** %tmp14, align 4 + %tmp15 = getelementptr inbounds %s1* %this, i32 0, i32 5 + store i8* %info, i8** %tmp15, align 4 + %tmp16 = getelementptr inbounds %s1* %this, i32 0, i32 6 + store i32* null, i32** %tmp16, align 4 + %tmp17 = getelementptr inbounds %s1* %this, i32 0, i32 7 + store i32* null, i32** %tmp17, align 4 + %tmp19 = getelementptr inbounds %s1* %this, i32 0, i32 10 + store i64 0, i64* %tmp19, align 4 + %tmp20 = getelementptr inbounds %s1* %this, i32 0, i32 0 + tail call arm_apcscc void @f1(%s3* %tmp20, i32* %s) nounwind + %tmp21 = shl i32 %format, 6 + %tmp22 = tail call arm_apcscc zeroext i8 @f2(i32 %format) nounwind + %toBoolnot = icmp eq i8 %tmp22, 0 + %tmp23 = zext i1 %toBoolnot to i32 + %flags.0 = or i32 %tmp23, %tmp21 + %tmp24 = shl i32 %flags.0, 16 + %asmtmp.i.i.i = tail call %0 asm sideeffect "\0A0:\09ldrex $1, [$2]\0A\09orr $1, $1, $3\0A\09strex $0, $1, [$2]\0A\09cmp $0, #0\0A\09bne 0b", "=&r,=&r,r,r,~{memory},~{cc}"(i32* %tmp1, i32 %tmp24) nounwind + %tmp25 = getelementptr inbounds %s1* %this, i32 0, i32 2, i32 0, i32 0 + volatile store i32 1, i32* %tmp25, align 4 + %tmp26 = icmp eq i32 %levels, 0 + br i1 %tmp26, label %return, label %bb4 + +bb4: + %l.09 = phi i32 [ %tmp28, %bb4 ], [ 0, %entry ] + %scevgep = getelementptr %s1* %this, i32 0, i32 11, i32 %l.09 + %scevgep10 = getelementptr i32* %rowbytes, i32 %l.09 + %tmp27 = load i32* %scevgep10, align 4 + store i32 %tmp27, i32* %scevgep, align 4 + %tmp28 = add i32 %l.09, 1 + %exitcond = icmp eq i32 %tmp28, %levels + br i1 %exitcond, label %return, label %bb4 + +return: + ret void +} + +declare arm_apcscc void @f1(%s3*, i32*) +declare arm_apcscc zeroext i8 @f2(i32) From jyasskin at google.com Tue Mar 16 00:54:54 2010 From: jyasskin at google.com (Jeffrey Yasskin) Date: Tue, 16 Mar 2010 05:54:54 -0000 Subject: [llvm-commits] [llvm] r98612 - /llvm/trunk/lib/ExecutionEngine/JIT/JITDebugRegisterer.cpp Message-ID: <20100316055454.C05DF2A6C12C@llvm.org> Author: jyasskin Date: Tue Mar 16 00:54:54 2010 New Revision: 98612 URL: http://llvm.org/viewvc/llvm-project?rev=98612&view=rev Log: Avoid a memory leak in JITDebugRegisterer. Modified: llvm/trunk/lib/ExecutionEngine/JIT/JITDebugRegisterer.cpp Modified: llvm/trunk/lib/ExecutionEngine/JIT/JITDebugRegisterer.cpp URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/ExecutionEngine/JIT/JITDebugRegisterer.cpp?rev=98612&r1=98611&r2=98612&view=diff ============================================================================== --- llvm/trunk/lib/ExecutionEngine/JIT/JITDebugRegisterer.cpp (original) +++ llvm/trunk/lib/ExecutionEngine/JIT/JITDebugRegisterer.cpp Tue Mar 16 00:54:54 2010 @@ -165,7 +165,7 @@ void JITDebugRegisterer::UnregisterFunctionInternal( RegisteredFunctionsMap::iterator I) { - jit_code_entry *JITCodeEntry = I->second.second; + jit_code_entry *&JITCodeEntry = I->second.second; // Acquire the lock and do the unregistration. { @@ -190,6 +190,9 @@ __jit_debug_register_code(); } + delete JITCodeEntry; + JITCodeEntry = NULL; + // Free the ELF file in memory. std::string &Buffer = I->second.first; Buffer.clear(); From sabre at nondot.org Tue Mar 16 01:30:18 2010 From: sabre at nondot.org (Chris Lattner) Date: Tue, 16 Mar 2010 06:30:18 -0000 Subject: [llvm-commits] [llvm] r98615 - /llvm/trunk/lib/Target/X86/X86InstrInfo.td Message-ID: <20100316063018.A3DAD2A6C12C@llvm.org> Author: lattner Date: Tue Mar 16 01:30:18 2010 New Revision: 98615 URL: http://llvm.org/viewvc/llvm-project?rev=98615&view=rev Log: fix the encoding of TAILJMPd. This fixes Benchmarks/Olden/bisort with the integrated assembler! Modified: llvm/trunk/lib/Target/X86/X86InstrInfo.td Modified: llvm/trunk/lib/Target/X86/X86InstrInfo.td URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Target/X86/X86InstrInfo.td?rev=98615&r1=98614&r2=98615&view=diff ============================================================================== --- llvm/trunk/lib/Target/X86/X86InstrInfo.td (original) +++ llvm/trunk/lib/Target/X86/X86InstrInfo.td Tue Mar 16 01:30:18 2010 @@ -724,8 +724,8 @@ // FIXME: The should be pseudo instructions that are lowered when going to // mcinst. - def TAILJMPd : Ii32<0xE9, RawFrm, (outs), - (ins i32imm_pcrel:$dst, variable_ops), + def TAILJMPd : Ii32PCRel<0xE9, RawFrm, (outs), + (ins i32imm_pcrel:$dst, variable_ops), "jmp\t$dst # TAILCALL", []>; def TAILJMPr : I<0xFF, MRM4r, (outs), (ins GR32_TC:$dst, variable_ops), From sabre at nondot.org Tue Mar 16 01:39:08 2010 From: sabre at nondot.org (Chris Lattner) Date: Tue, 16 Mar 2010 06:39:08 -0000 Subject: [llvm-commits] [llvm] r98616 - /llvm/trunk/lib/Target/X86/X86Instr64bit.td Message-ID: <20100316063908.86E2C2A6C12C@llvm.org> Author: lattner Date: Tue Mar 16 01:39:08 2010 New Revision: 98616 URL: http://llvm.org/viewvc/llvm-project?rev=98616&view=rev Log: fix the same bug on the x86-64 side of the fence. Modified: llvm/trunk/lib/Target/X86/X86Instr64bit.td Modified: llvm/trunk/lib/Target/X86/X86Instr64bit.td URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Target/X86/X86Instr64bit.td?rev=98616&r1=98615&r2=98616&view=diff ============================================================================== --- llvm/trunk/lib/Target/X86/X86Instr64bit.td (original) +++ llvm/trunk/lib/Target/X86/X86Instr64bit.td Tue Mar 16 01:39:08 2010 @@ -202,7 +202,7 @@ (ins i64mem_TC:$dst, i32imm:$offset, variable_ops), "#TC_RETURN $dst $offset", []>; - def TAILJMPd64 : Ii32<0xE9, RawFrm, (outs), + def TAILJMPd64 : Ii32PCRel<0xE9, RawFrm, (outs), (ins i64i32imm_pcrel:$dst, variable_ops), "jmp\t$dst # TAILCALL", []>; def TAILJMPr64 : I<0xFF, MRM4r, (outs), (ins GR64_TC:$dst, variable_ops), From daniel at zuster.org Tue Mar 16 01:40:46 2010 From: daniel at zuster.org (Daniel Dunbar) Date: Tue, 16 Mar 2010 06:40:46 -0000 Subject: [llvm-commits] [zorg] r98617 - /zorg/trunk/buildbot/osuosl/master/config/slaves.py Message-ID: <20100316064046.478FA2A6C12C@llvm.org> Author: ddunbar Date: Tue Mar 16 01:40:46 2010 New Revision: 98617 URL: http://llvm.org/viewvc/llvm-project?rev=98617&view=rev Log: Add a new ARM machine from Nick. Modified: zorg/trunk/buildbot/osuosl/master/config/slaves.py Modified: zorg/trunk/buildbot/osuosl/master/config/slaves.py URL: http://llvm.org/viewvc/llvm-project/zorg/trunk/buildbot/osuosl/master/config/slaves.py?rev=98617&r1=98616&r2=98617&view=diff ============================================================================== --- zorg/trunk/buildbot/osuosl/master/config/slaves.py (original) +++ zorg/trunk/buildbot/osuosl/master/config/slaves.py Tue Mar 16 01:40:46 2010 @@ -14,8 +14,11 @@ # FreeBSD zero.sajd.net 9.0-CURRENT i386 create_slave("freebsd1", properties={'jobs' : 1}), - # A PowerPC Linux machine. 900MHz G3 processor with 256MB of RAM. - create_slave("nick1"), + # PowerPC Linux machine. 900MHz G3 processor with 256MB of RAM. + create_slave("nick1", properties={'jobs' : 1}, max_builds=1), + + # Linux, Beagleboard, Cortex A8, 256MB RAM. + create_slave("nick2", properties={'jobs' : 1}, max_builds=1), # Core 2 Duo running Ubuntu. create_slave("dunbar1", properties={'jobs' : 2}, max_builds=1), From sabre at nondot.org Tue Mar 16 01:41:47 2010 From: sabre at nondot.org (Chris Lattner) Date: Tue, 16 Mar 2010 06:41:47 -0000 Subject: [llvm-commits] [llvm] r98618 - in /llvm/trunk/tools/bugpoint: ExecutionDriver.cpp ToolRunner.cpp ToolRunner.h Message-ID: <20100316064147.57BF12A6C12C@llvm.org> Author: lattner Date: Tue Mar 16 01:41:47 2010 New Revision: 98618 URL: http://llvm.org/viewvc/llvm-project?rev=98618&view=rev Log: add support for bugpointing the integrated assembler. Something like this works for me: bugpoint Output/bisort.llvm.bc -run-llc-ia -safe-run-llc This uses llc with the integrated assembler as the test compiler and llc without it as the safe compiler. Modified: llvm/trunk/tools/bugpoint/ExecutionDriver.cpp llvm/trunk/tools/bugpoint/ToolRunner.cpp llvm/trunk/tools/bugpoint/ToolRunner.h Modified: llvm/trunk/tools/bugpoint/ExecutionDriver.cpp URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/tools/bugpoint/ExecutionDriver.cpp?rev=98618&r1=98617&r2=98618&view=diff ============================================================================== --- llvm/trunk/tools/bugpoint/ExecutionDriver.cpp (original) +++ llvm/trunk/tools/bugpoint/ExecutionDriver.cpp Tue Mar 16 01:41:47 2010 @@ -28,7 +28,7 @@ // for miscompilation. // enum OutputType { - AutoPick, RunLLI, RunJIT, RunLLC, RunCBE, CBE_bug, LLC_Safe, Custom + AutoPick, RunLLI, RunJIT, RunLLC, RunLLCIA, RunCBE, CBE_bug, LLC_Safe,Custom }; cl::opt @@ -45,6 +45,8 @@ "Execute with the interpreter"), clEnumValN(RunJIT, "run-jit", "Execute with JIT"), clEnumValN(RunLLC, "run-llc", "Compile with LLC"), + clEnumValN(RunLLCIA, "run-llc-ia", + "Compile with LLC with integrated assembler"), clEnumValN(RunCBE, "run-cbe", "Compile with CBE"), clEnumValN(CBE_bug,"cbe-bug", "Find CBE bugs"), clEnumValN(LLC_Safe, "llc-safe", "Use LLC for all"), @@ -168,9 +170,11 @@ &ToolArgv); break; case RunLLC: + case RunLLCIA: case LLC_Safe: Interpreter = AbstractInterpreter::createLLC(getToolName(), Message, - &ToolArgv, &GCCToolArgv); + &ToolArgv, &GCCToolArgv, + InterpreterSel == RunLLCIA); break; case RunJIT: Interpreter = AbstractInterpreter::createJIT(getToolName(), Message, @@ -244,10 +248,12 @@ } break; case RunLLC: + case RunLLCIA: SafeToolArgs.push_back("--relocation-model=pic"); SafeInterpreter = AbstractInterpreter::createLLC(Path.c_str(), Message, &SafeToolArgs, - &GCCToolArgv); + &GCCToolArgv, + SafeInterpreterSel == RunLLCIA); break; case RunCBE: SafeInterpreter = AbstractInterpreter::createCBE(Path.c_str(), Message, Modified: llvm/trunk/tools/bugpoint/ToolRunner.cpp URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/tools/bugpoint/ToolRunner.cpp?rev=98618&r1=98617&r2=98618&view=diff ============================================================================== --- llvm/trunk/tools/bugpoint/ToolRunner.cpp (original) +++ llvm/trunk/tools/bugpoint/ToolRunner.cpp Tue Mar 16 01:41:47 2010 @@ -141,7 +141,7 @@ for (const char **Arg = Args; *Arg; ++Arg) OS << " " << *Arg; OS << "\n"; - + // Rerun the compiler, capturing any error messages to print them. sys::Path ErrorFilename("bugpoint.program_error_messages"); std::string ErrMsg; @@ -352,7 +352,8 @@ // GCC::FileType LLC::OutputCode(const std::string &Bitcode, sys::Path &OutputAsmFile) { - sys::Path uniqueFile(Bitcode+".llc.s"); + const char *Suffix = (UseIntegratedAssembler ? ".llc.o" : ".llc.s"); + sys::Path uniqueFile(Bitcode + Suffix); std::string ErrMsg; if (uniqueFile.makeUnique(true, &ErrMsg)) { errs() << "Error making unique filename: " << ErrMsg << "\n"; @@ -360,18 +361,23 @@ } OutputAsmFile = uniqueFile; std::vector LLCArgs; - LLCArgs.push_back (LLCPath.c_str()); + LLCArgs.push_back(LLCPath.c_str()); // Add any extra LLC args. for (unsigned i = 0, e = ToolArgs.size(); i != e; ++i) LLCArgs.push_back(ToolArgs[i].c_str()); - LLCArgs.push_back ("-o"); - LLCArgs.push_back (OutputAsmFile.c_str()); // Output to the Asm file - LLCArgs.push_back (Bitcode.c_str()); // This is the input bitcode + LLCArgs.push_back("-o"); + LLCArgs.push_back(OutputAsmFile.c_str()); // Output to the Asm file + LLCArgs.push_back(Bitcode.c_str()); // This is the input bitcode + + if (UseIntegratedAssembler) + LLCArgs.push_back("-filetype=obj"); + LLCArgs.push_back (0); - outs() << ""; outs().flush(); + outs() << (UseIntegratedAssembler ? "" : ""); + outs().flush(); DEBUG(errs() << "\nAbout to run:\t"; for (unsigned i=0, e = LLCArgs.size()-1; i != e; ++i) errs() << " " << LLCArgs[i]; @@ -381,7 +387,7 @@ sys::Path(), sys::Path(), sys::Path())) ProcessFailure(sys::Path(LLCPath), &LLCArgs[0]); - return GCC::AsmFile; + return UseIntegratedAssembler ? GCC::ObjectFile : GCC::AsmFile; } void LLC::compileProgram(const std::string &Bitcode) { @@ -400,7 +406,7 @@ unsigned MemoryLimit) { sys::Path OutputAsmFile; - OutputCode(Bitcode, OutputAsmFile); + GCC::FileType FileKind = OutputCode(Bitcode, OutputAsmFile); FileRemover OutFileRemover(OutputAsmFile, !SaveTemps); std::vector GCCArgs(ArgsForGCC); @@ -408,7 +414,7 @@ GCCArgs.insert(GCCArgs.end(), gccArgs.begin(), gccArgs.end()); // Assuming LLC worked, compile the result with GCC and run it. - return gcc->ExecuteProgram(OutputAsmFile.str(), Args, GCC::AsmFile, + return gcc->ExecuteProgram(OutputAsmFile.str(), Args, FileKind, InputFile, OutputFile, GCCArgs, Timeout, MemoryLimit); } @@ -418,7 +424,8 @@ LLC *AbstractInterpreter::createLLC(const char *Argv0, std::string &Message, const std::vector *Args, - const std::vector *GCCArgs) { + const std::vector *GCCArgs, + bool UseIntegratedAssembler) { std::string LLCPath = FindExecutable("llc", Argv0, (void *)(intptr_t)&createLLC).str(); if (LLCPath.empty()) { @@ -432,7 +439,7 @@ errs() << Message << "\n"; exit(1); } - return new LLC(LLCPath, gcc, Args, GCCArgs); + return new LLC(LLCPath, gcc, Args, GCCArgs, UseIntegratedAssembler); } //===---------------------------------------------------------------------===// @@ -605,17 +612,14 @@ // GCC abstraction // -static bool -IsARMArchitecture(std::vector Args) -{ +static bool IsARMArchitecture(std::vector Args) { for (std::vector::const_iterator I = Args.begin(), E = Args.end(); I != E; ++I) { StringRef S(*I); if (!S.equals_lower("-arch")) { ++I; - if (I != E && !S.substr(0, strlen("arm")).equals_lower("arm")) { + if (I != E && !S.substr(0, strlen("arm")).equals_lower("arm")) return true; - } } } @@ -634,26 +638,33 @@ GCCArgs.push_back(GCCPath.c_str()); + if (TargetTriple.getArch() == Triple::x86) + GCCArgs.push_back("-m32"); + for (std::vector::const_iterator I = gccArgs.begin(), E = gccArgs.end(); I != E; ++I) GCCArgs.push_back(I->c_str()); // Specify -x explicitly in case the extension is wonky - GCCArgs.push_back("-x"); - if (fileType == CFile) { - GCCArgs.push_back("c"); - GCCArgs.push_back("-fno-strict-aliasing"); - } else { - GCCArgs.push_back("assembler"); - - // For ARM architectures we don't want this flag. bugpoint isn't - // explicitly told what architecture it is working on, so we get - // it from gcc flags - if ((TargetTriple.getOS() == Triple::Darwin) && - !IsARMArchitecture(ArgsForGCC)) - GCCArgs.push_back("-force_cpusubtype_ALL"); + if (fileType != ObjectFile) { + GCCArgs.push_back("-x"); + if (fileType == CFile) { + GCCArgs.push_back("c"); + GCCArgs.push_back("-fno-strict-aliasing"); + } else { + GCCArgs.push_back("assembler"); + + // For ARM architectures we don't want this flag. bugpoint isn't + // explicitly told what architecture it is working on, so we get + // it from gcc flags + if ((TargetTriple.getOS() == Triple::Darwin) && + !IsARMArchitecture(ArgsForGCC)) + GCCArgs.push_back("-force_cpusubtype_ALL"); + } } - GCCArgs.push_back(ProgramFile.c_str()); // Specify the input filename... + + GCCArgs.push_back(ProgramFile.c_str()); // Specify the input filename. + GCCArgs.push_back("-x"); GCCArgs.push_back("none"); GCCArgs.push_back("-o"); @@ -765,13 +776,18 @@ GCCArgs.push_back(GCCPath.c_str()); + if (TargetTriple.getArch() == Triple::x86) + GCCArgs.push_back("-m32"); + for (std::vector::const_iterator I = gccArgs.begin(), E = gccArgs.end(); I != E; ++I) GCCArgs.push_back(I->c_str()); // Compile the C/asm file into a shared object - GCCArgs.push_back("-x"); - GCCArgs.push_back(fileType == AsmFile ? "assembler" : "c"); + if (fileType != ObjectFile) { + GCCArgs.push_back("-x"); + GCCArgs.push_back(fileType == AsmFile ? "assembler" : "c"); + } GCCArgs.push_back("-fno-strict-aliasing"); GCCArgs.push_back(InputFile.c_str()); // Specify the input filename. GCCArgs.push_back("-x"); Modified: llvm/trunk/tools/bugpoint/ToolRunner.h URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/tools/bugpoint/ToolRunner.h?rev=98618&r1=98617&r2=98618&view=diff ============================================================================== --- llvm/trunk/tools/bugpoint/ToolRunner.h (original) +++ llvm/trunk/tools/bugpoint/ToolRunner.h Tue Mar 16 01:41:47 2010 @@ -58,7 +58,7 @@ if (GCCArgs) gccArgs = *GCCArgs; } public: - enum FileType { AsmFile, CFile }; + enum FileType { AsmFile, ObjectFile, CFile }; static GCC *create(std::string &Message, const std::vector *Args); @@ -101,7 +101,8 @@ const std::vector *GCCArgs = 0); static LLC *createLLC(const char *Argv0, std::string &Message, const std::vector *Args = 0, - const std::vector *GCCArgs = 0); + const std::vector *GCCArgs = 0, + bool UseIntegratedAssembler = false); static AbstractInterpreter* createLLI(const char *Argv0, std::string &Message, const std::vector *Args=0); @@ -195,11 +196,14 @@ std::vector ToolArgs; // Extra args to pass to LLC. std::vector gccArgs; // Extra args to pass to GCC. GCC *gcc; + bool UseIntegratedAssembler; public: LLC(const std::string &llcPath, GCC *Gcc, const std::vector *Args, - const std::vector *GCCArgs) - : LLCPath(llcPath), gcc(Gcc) { + const std::vector *GCCArgs, + bool useIntegratedAssembler) + : LLCPath(llcPath), gcc(Gcc), + UseIntegratedAssembler(useIntegratedAssembler) { ToolArgs.clear(); if (Args) ToolArgs = *Args; if (GCCArgs) gccArgs = *GCCArgs; From daniel at zuster.org Tue Mar 16 01:42:55 2010 From: daniel at zuster.org (Daniel Dunbar) Date: Tue, 16 Mar 2010 06:42:55 -0000 Subject: [llvm-commits] [zorg] r98619 - /zorg/trunk/buildbot/osuosl/master/config/builders.py Message-ID: <20100316064255.2E8312A6C12C@llvm.org> Author: ddunbar Date: Tue Mar 16 01:42:55 2010 New Revision: 98619 URL: http://llvm.org/viewvc/llvm-project?rev=98619&view=rev Log: Add a bunch of new Linux builders, notably some valgrind testers on the new OSUOSL machines. Modified: zorg/trunk/buildbot/osuosl/master/config/builders.py Modified: zorg/trunk/buildbot/osuosl/master/config/builders.py URL: http://llvm.org/viewvc/llvm-project/zorg/trunk/buildbot/osuosl/master/config/builders.py?rev=98619&r1=98618&r2=98619&view=diff ============================================================================== --- zorg/trunk/buildbot/osuosl/master/config/builders.py (original) +++ zorg/trunk/buildbot/osuosl/master/config/builders.py Tue Mar 16 01:42:55 2010 @@ -1,7 +1,6 @@ from zorg.buildbot.builders import ClangBuilder, LLVMBuilder, LLVMGCCBuilder - -from zorg.buildbot.builders import DragonEggBuilder -reload(DragonEggBuilder) +reload(LLVMBuilder) +from zorg.buildbot.builders import ClangBuilder, LLVMBuilder, LLVMGCCBuilder from zorg.buildbot.builders import DragonEggBuilder # Plain LLVM builders. @@ -24,6 +23,16 @@ 'builddir':"llvm-arm-linux", 'factory': LLVMBuilder.getLLVMBuildFactory("arm-pc-linux-gnu", jobs=1, clean=False, timeout=40)}, + {'name': "llvm-i686-linux-vg", + 'slavenames':["osu8"], + 'builddir':"llvm-i686-linux-vg", + 'factory': LLVMBuilder.getLLVMBuildFactory("i686-pc-linux-gnu", valgrind=True), + 'category':'llvm.exp'}, + {'name': "llvm-x86_64-linux-vg", + 'slavenames':["osu7"], + 'builddir':"llvm-x86_64-linux-vg", + 'factory': LLVMBuilder.getLLVMBuildFactory("x86_64-pc-linux-gnu", valgrind=True), + 'category':'llvm.exp'}, ] # Offline. @@ -56,10 +65,6 @@ 'slavenames':["osu2"], 'builddir':"llvm-x86_64-linux-checks", 'factory':LLVMBuilder.getLLVMBuildFactory("x86_64-pc-linux-gnu", jobs=10, expensive_checks=True)} -{'name' : "llvm-gcc-x86_64-linux-selfhost", - 'slavenames':["osu2"], - 'builddir':"llvm-gcc-x86_64-linux-selfhost", - 'factory':LLVMGCCBuilder.getLLVMGCCBuildFactory(10)} # Clang builders. def _get_clang_builders(): @@ -85,6 +90,12 @@ 'slavenames' :['dunbar-win32-2'], 'builddir' :"clang-i686-xp-msvc9", 'factory' : ClangBuilder.getClangMSVCBuildFactory(jobs=2)}, + + {'name': "clang-x86_64-linux-vg", + 'slavenames':["osu7"], + 'builddir':"clang-x86_64-linux-vg", + 'factory': ClangBuilder.getClangBuildFactory(valgrind=True)}, + {'name' : "clang-x86_64-darwin10-selfhost", 'slavenames' : ["dunbar-darwin10"], 'builddir' : "clang-x86_64-darwin10-selfhost", @@ -128,11 +139,37 @@ stage2_config='Release'), 'category' : 'clang.exp' }, + {'name' : "clang-i686-linux-selfhost-rel", + 'slavenames' : ["osu8"], + 'builddir' : "clang-i686-linux-selfhost-rel", + 'factory' : ClangBuilder.getClangBuildFactory(triple='i686-pc-linux-gnu', + useTwoStage=True, + stage1_config='Release', + stage2_config='Release'), + 'category' : 'clang.exp' }, + + {'name' : "llvm-gcc-x86_64-linux-selfhost", + 'slavenames':["osu7"], + 'builddir':"llvm-gcc-x86_64-linux-selfhost", + 'factory':LLVMGCCBuilder.getLLVMGCCBuildFactory(triple='x86_64-pc-linux-gnu', + extra_configure_args=['--disable-multilib']), + 'category' : 'llvm-gcc.exp' }, + + {'name' : "clang-x86_64-linux-selfhost-rel", + 'slavenames' : ["osu7"], + 'builddir' : "clang-x86_64-linux-selfhost-rel", + 'factory' : ClangBuilder.getClangBuildFactory(triple='x86_64-pc-linux-gnu', + useTwoStage=True, + stage1_config='Release', + stage2_config='Release'), + 'category' : 'clang.exp' }, + {'name' : 'dragonegg-x86_64-linux', 'slavenames' : ['baldrick16'], 'builddir' : 'dragonegg-x86_64-linux', 'factory' : DragonEggBuilder.getBuildFactory(triple='x86_64-pc-linux-gnu'), 'category' : 'dragonegg.exp' }, + ] def get_builders(): @@ -153,11 +190,6 @@ # Random other unused builders... -{'name': "clang-x86_64-linux-vg", - 'slavenames':["osu2"], - 'builddir':"clang-x86_64-linux-vg", - 'factory': ClangBuilder.getClangBuildFactory(valgrind=True), - 'category':'clang.exp'} {'name': "clang-x86_64-openbsd", 'slavenames':["ocean1"], 'builddir':"clang-x86_64-openbsd", From daniel at zuster.org Tue Mar 16 01:44:03 2010 From: daniel at zuster.org (Daniel Dunbar) Date: Tue, 16 Mar 2010 06:44:03 -0000 Subject: [llvm-commits] [zorg] r98620 - /zorg/trunk/zorg/buildbot/builders/LLVMBuilder.py Message-ID: <20100316064403.6104F2A6C12C@llvm.org> Author: ddunbar Date: Tue Mar 16 01:44:03 2010 New Revision: 98620 URL: http://llvm.org/viewvc/llvm-project?rev=98620&view=rev Log: Add valgrind argument to getLLVMBuildFactory. Modified: zorg/trunk/zorg/buildbot/builders/LLVMBuilder.py Modified: zorg/trunk/zorg/buildbot/builders/LLVMBuilder.py URL: http://llvm.org/viewvc/llvm-project/zorg/trunk/zorg/buildbot/builders/LLVMBuilder.py?rev=98620&r1=98619&r2=98620&view=diff ============================================================================== --- zorg/trunk/zorg/buildbot/builders/LLVMBuilder.py (original) +++ zorg/trunk/zorg/buildbot/builders/LLVMBuilder.py Tue Mar 16 01:44:03 2010 @@ -10,7 +10,7 @@ from zorg.buildbot.commands.ClangTestCommand import ClangTestCommand def getLLVMBuildFactory(triple=None, clean=True, test=True, - expensive_checks=False, examples=False, + expensive_checks=False, examples=False, valgrind=False, jobs='%(jobs)s', timeout=20, make='make', enable_shared=False): f = buildbot.process.factory.BuildFactory() @@ -70,8 +70,13 @@ workdir='llvm', timeout=timeout*60)) if test: + litTestArgs = '-v' + if valgrind: + litTestArgs += ' --vg ' + litTestArgs += ' --vg-arg --leak-check=full' f.addStep(ClangTestCommand(name='test-llvm', - command=[make, "check-lit", "VERBOSE=1"], + command=[make, "check-lit", "VERBOSE=1", + "LIT_ARGS=%s" % litTestArgs], description=["testing", "llvm"], descriptionDone=["test", "llvm"], workdir='llvm')) From ggreif at gmail.com Tue Mar 16 04:55:46 2010 From: ggreif at gmail.com (Gabor Greif) Date: Tue, 16 Mar 2010 09:55:46 -0000 Subject: [llvm-commits] [llvm] r98623 - /llvm/trunk/unittests/VMCore/InstructionsTest.cpp Message-ID: <20100316095546.362F12A6C12C@llvm.org> Author: ggreif Date: Tue Mar 16 04:55:46 2010 New Revision: 98623 URL: http://llvm.org/viewvc/llvm-project?rev=98623&view=rev Log: begin humbly with a repro of PR6589 Added: llvm/trunk/unittests/VMCore/InstructionsTest.cpp Added: llvm/trunk/unittests/VMCore/InstructionsTest.cpp URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/unittests/VMCore/InstructionsTest.cpp?rev=98623&view=auto ============================================================================== --- llvm/trunk/unittests/VMCore/InstructionsTest.cpp (added) +++ llvm/trunk/unittests/VMCore/InstructionsTest.cpp Tue Mar 16 04:55:46 2010 @@ -0,0 +1,26 @@ +//===- llvm/unittest/VMCore/InstructionsTest.cpp - Instructions unit tests ===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "llvm/Instructions.h" +#include "llvm/LLVMContext.h" +#include "gtest/gtest.h" + +namespace llvm { +namespace { + +TEST(InstructionsTest, ReturnInst_0) { + LLVMContext &C(getGlobalContext()); + + // reproduction recipe for PR6589 + const ReturnInst* r0 = ReturnInst::Create(C); + EXPECT_NE(r0->op_begin(), r0->op_end()); +} + +} // end anonymous namespace +} // end namespace llvm From ggreif at gmail.com Tue Mar 16 05:59:48 2010 From: ggreif at gmail.com (Gabor Greif) Date: Tue, 16 Mar 2010 10:59:48 -0000 Subject: [llvm-commits] [llvm] r98624 - in /llvm/trunk: include/llvm/Instructions.h include/llvm/OperandTraits.h unittests/VMCore/InstructionsTest.cpp Message-ID: <20100316105948.3C8112A6C12C@llvm.org> Author: ggreif Date: Tue Mar 16 05:59:48 2010 New Revision: 98624 URL: http://llvm.org/viewvc/llvm-project?rev=98624&view=rev Log: fix PR6589 adjusted unittest I have added some doxygen to OptionalOperandTraits, so hopefully there will be no confusion in the future. Incidentally OptionalOperandTraits is not used any more (IIUC), but the obvious client would be BranchInstr, and I plan to rearrange it that way. Modified: llvm/trunk/include/llvm/Instructions.h llvm/trunk/include/llvm/OperandTraits.h llvm/trunk/unittests/VMCore/InstructionsTest.cpp Modified: llvm/trunk/include/llvm/Instructions.h URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/Instructions.h?rev=98624&r1=98623&r2=98624&view=diff ============================================================================== --- llvm/trunk/include/llvm/Instructions.h (original) +++ llvm/trunk/include/llvm/Instructions.h Tue Mar 16 05:59:48 2010 @@ -1984,7 +1984,7 @@ }; template <> -struct OperandTraits : public OptionalOperandTraits<> { +struct OperandTraits : public VariadicOperandTraits<> { }; DEFINE_TRANSPARENT_OPERAND_ACCESSORS(ReturnInst, Value) Modified: llvm/trunk/include/llvm/OperandTraits.h URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/OperandTraits.h?rev=98624&r1=98623&r2=98624&view=diff ============================================================================== --- llvm/trunk/include/llvm/OperandTraits.h (original) +++ llvm/trunk/include/llvm/OperandTraits.h Tue Mar 16 05:59:48 2010 @@ -20,7 +20,7 @@ namespace llvm { //===----------------------------------------------------------------------===// -// FixedNumOperands Trait Class +// FixedNumOperand Trait Class //===----------------------------------------------------------------------===// /// FixedNumOperandTraits - determine the allocation regime of the Use array @@ -51,9 +51,12 @@ }; //===----------------------------------------------------------------------===// -// OptionalOperands Trait Class +// OptionalOperand Trait Class //===----------------------------------------------------------------------===// +/// OptionalOperandTraits - when the number of operands may change at runtime. +/// Naturally it may only decrease, because the allocations may not change. + template struct OptionalOperandTraits : public FixedNumOperandTraits { static unsigned operands(const User *U) { Modified: llvm/trunk/unittests/VMCore/InstructionsTest.cpp URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/unittests/VMCore/InstructionsTest.cpp?rev=98624&r1=98623&r2=98624&view=diff ============================================================================== --- llvm/trunk/unittests/VMCore/InstructionsTest.cpp (original) +++ llvm/trunk/unittests/VMCore/InstructionsTest.cpp Tue Mar 16 05:59:48 2010 @@ -14,12 +14,12 @@ namespace llvm { namespace { -TEST(InstructionsTest, ReturnInst_0) { +TEST(InstructionsTest, ReturnInst) { LLVMContext &C(getGlobalContext()); - // reproduction recipe for PR6589 + // test for PR6589 const ReturnInst* r0 = ReturnInst::Create(C); - EXPECT_NE(r0->op_begin(), r0->op_end()); + EXPECT_EQ(r0->op_begin(), r0->op_end()); } } // end anonymous namespace From ggreif at gmail.com Tue Mar 16 06:24:53 2010 From: ggreif at gmail.com (Gabor Greif) Date: Tue, 16 Mar 2010 11:24:53 -0000 Subject: [llvm-commits] [llvm] r98625 - /llvm/trunk/unittests/VMCore/InstructionsTest.cpp Message-ID: <20100316112453.391162A6C12C@llvm.org> Author: ggreif Date: Tue Mar 16 06:24:53 2010 New Revision: 98625 URL: http://llvm.org/viewvc/llvm-project?rev=98625&view=rev Log: add single return tests Modified: llvm/trunk/unittests/VMCore/InstructionsTest.cpp Modified: llvm/trunk/unittests/VMCore/InstructionsTest.cpp URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/unittests/VMCore/InstructionsTest.cpp?rev=98625&r1=98624&r2=98625&view=diff ============================================================================== --- llvm/trunk/unittests/VMCore/InstructionsTest.cpp (original) +++ llvm/trunk/unittests/VMCore/InstructionsTest.cpp Tue Mar 16 06:24:53 2010 @@ -8,6 +8,7 @@ //===----------------------------------------------------------------------===// #include "llvm/Instructions.h" +#include "llvm/DerivedTypes.h" #include "llvm/LLVMContext.h" #include "gtest/gtest.h" @@ -20,6 +21,16 @@ // test for PR6589 const ReturnInst* r0 = ReturnInst::Create(C); EXPECT_EQ(r0->op_begin(), r0->op_end()); + + const IntegerType* Int1 = IntegerType::get(C, 1); + Constant* One = ConstantInt::get(Int1, 1, true); + const ReturnInst* r1 = ReturnInst::Create(C, One); + User::const_op_iterator b(r1->op_begin()); + EXPECT_NE(b, r1->op_end()); + EXPECT_EQ(*b, One); + EXPECT_EQ(r1->getOperand(0), One); + ++b; + EXPECT_EQ(b, r1->op_end()); } } // end anonymous namespace From baldrick at free.fr Tue Mar 16 06:35:32 2010 From: baldrick at free.fr (Duncan Sands) Date: Tue, 16 Mar 2010 11:35:32 -0000 Subject: [llvm-commits] [llvm-gcc-4.2] r98626 - /llvm-gcc-4.2/trunk/gcc/llvm-backend.cpp Message-ID: <20100316113532.C19AA2A6C12C@llvm.org> Author: baldrick Date: Tue Mar 16 06:35:32 2010 New Revision: 98626 URL: http://llvm.org/viewvc/llvm-project?rev=98626&view=rev Log: If a global variable is initialized by a code sequence, then do not zero initialize it: using 'undef' makes it easier for the optimizers to sink initialization code into the initializer for the global. It is not clear if this is always correct, since it relies on the code sequence not somehow making use of the global being zero initialized. My limited experiments suggest that everything is fine. This is partial progress towards getting better code out of the testcase in PR6551. Modified: llvm-gcc-4.2/trunk/gcc/llvm-backend.cpp Modified: llvm-gcc-4.2/trunk/gcc/llvm-backend.cpp URL: http://llvm.org/viewvc/llvm-project/llvm-gcc-4.2/trunk/gcc/llvm-backend.cpp?rev=98626&r1=98625&r2=98626&view=diff ============================================================================== --- llvm-gcc-4.2/trunk/gcc/llvm-backend.cpp (original) +++ llvm-gcc-4.2/trunk/gcc/llvm-backend.cpp Tue Mar 16 06:35:32 2010 @@ -1320,10 +1320,17 @@ // Convert the initializer over. Constant *Init; if (DECL_INITIAL(decl) == 0 || DECL_INITIAL(decl) == error_mark_node) { - // This global should be zero initialized. Reconvert the type in case the + // This global does not have an explicit initializer. This usually means + // that it should be zero initialized. Reconvert the type in case the // forward def of the global and the real def differ in type (e.g. declared // as 'int A[]', and defined as 'int A[100]'). - Init = Constant::getNullValue(ConvertType(TREE_TYPE(decl))); + if (TYPE_NEEDS_CONSTRUCTING(TREE_TYPE(decl))) { + // The global will be initialized by a code sequence - it does not need to + // be zero initialized. + Init = UndefValue::get(ConvertType(TREE_TYPE(decl))); + } else { + Init = Constant::getNullValue(ConvertType(TREE_TYPE(decl))); + } } else { assert((TREE_CONSTANT(DECL_INITIAL(decl)) || TREE_CODE(DECL_INITIAL(decl)) == STRING_CST) && From baldrick at free.fr Tue Mar 16 06:36:35 2010 From: baldrick at free.fr (Duncan Sands) Date: Tue, 16 Mar 2010 11:36:35 -0000 Subject: [llvm-commits] [llvm] r98627 - /llvm/trunk/test/FrontendC++/2010-03-16-SinkStores.cpp Message-ID: <20100316113635.3573A2A6C12C@llvm.org> Author: baldrick Date: Tue Mar 16 06:36:35 2010 New Revision: 98627 URL: http://llvm.org/viewvc/llvm-project?rev=98627&view=rev Log: Check that P is not zero initialized. Added: llvm/trunk/test/FrontendC++/2010-03-16-SinkStores.cpp Added: llvm/trunk/test/FrontendC++/2010-03-16-SinkStores.cpp URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/FrontendC%2B%2B/2010-03-16-SinkStores.cpp?rev=98627&view=auto ============================================================================== --- llvm/trunk/test/FrontendC++/2010-03-16-SinkStores.cpp (added) +++ llvm/trunk/test/FrontendC++/2010-03-16-SinkStores.cpp Tue Mar 16 06:36:35 2010 @@ -0,0 +1,11 @@ +// RUN: %llvmgxx -S %s -o - | FileCheck %s + +#include + +typedef std::pair P; +// CHECK: @_ZZ1fvE1X {{.*}} undef + +P f() { + static const P X = P(1,2); + return X; +} From ggreif at gmail.com Tue Mar 16 07:32:03 2010 From: ggreif at gmail.com (Gabor Greif) Date: Tue, 16 Mar 2010 12:32:03 -0000 Subject: [llvm-commits] [llvm] r98628 - /llvm/trunk/unittests/VMCore/InstructionsTest.cpp Message-ID: <20100316123203.A2DA42A6C12C@llvm.org> Author: ggreif Date: Tue Mar 16 07:32:03 2010 New Revision: 98628 URL: http://llvm.org/viewvc/llvm-project?rev=98628&view=rev Log: appease valgrind testers Modified: llvm/trunk/unittests/VMCore/InstructionsTest.cpp Modified: llvm/trunk/unittests/VMCore/InstructionsTest.cpp URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/unittests/VMCore/InstructionsTest.cpp?rev=98628&r1=98627&r2=98628&view=diff ============================================================================== --- llvm/trunk/unittests/VMCore/InstructionsTest.cpp (original) +++ llvm/trunk/unittests/VMCore/InstructionsTest.cpp Tue Mar 16 07:32:03 2010 @@ -31,6 +31,10 @@ EXPECT_EQ(r1->getOperand(0), One); ++b; EXPECT_EQ(b, r1->op_end()); + + // clean up + delete r0; + delete r1; } } // end anonymous namespace From daniel at zuster.org Tue Mar 16 10:20:03 2010 From: daniel at zuster.org (Daniel Dunbar) Date: Tue, 16 Mar 2010 08:20:03 -0700 Subject: [llvm-commits] Extract MachObjectWriter class to own header and code files In-Reply-To: <9719867c1003151801u5f4f4de2t1403eacc5eddf2b9@mail.gmail.com> References: <9719867c1003151006r720d53cewebc80de9802ed238@mail.gmail.com> <6a8523d61003151731v66234328qd84112c1d364a8a7@mail.gmail.com> <9719867c1003151801u5f4f4de2t1403eacc5eddf2b9@mail.gmail.com> Message-ID: <6a8523d61003160820r356df606p65747ce2c0f3c668@mail.gmail.com> On Mon, Mar 15, 2010 at 6:01 PM, Aaron Gray wrote: > On 16 March 2010 00:31, Daniel Dunbar wrote: >> >> Hi Aaron, >> >> This has been on my list, but for the time being I find it convenient >> to have all the code in the same place. I also want to factor out a >> few more minor things before splitting in the target independent >> assembler and the object file writer. >> >> Is this blocking work you are hoping to do? > > Hi Daniel, > It would be good to get to the stage where I can work on the COFFWriter and > COFFStreamer. Ok. Do you mind waiting ~a week? > Basically I can wait but I thought a few file and class wise normalizations > would not go a miss :) > Also I wanted to introduce a common ObjectWriter abstract class for > MachObjectWriter, ELFObjectWriter, and COFFWriter, with Write and virtual > WriteObject methods. Right. I have this stuff planned out in my head, along similar lines. I'll try to get it in the next week but right now I wanted to get x86_64 Mach-O support up, which gives two concrete implementations to factor for. Work for you? - Daniel > I had worked on the older COFFWriter and got that nearly working with > LLVM-GCC so would like to get back to where I was progress wise. > Hope not to rock the boat :) > Aaron > >> >> On Mon, Mar 15, 2010 at 10:06 AM, Aaron Gray >> wrote: >> > Hi, >> > This patch extracts 'class MachObjectWriter' into its own .h and .cpp >> > files. >> > Tested on MSVC and Cygwin. >> > Aaron >> > >> > _______________________________________________ >> > llvm-commits mailing list >> > llvm-commits at cs.uiuc.edu >> > http://lists.cs.uiuc.edu/mailman/listinfo/llvm-commits >> > >> > > > From ggreif at gmail.com Tue Mar 16 10:26:09 2010 From: ggreif at gmail.com (Gabor Greif) Date: Tue, 16 Mar 2010 15:26:09 -0000 Subject: [llvm-commits] [llvm] r98632 - /llvm/trunk/unittests/VMCore/InstructionsTest.cpp Message-ID: <20100316152609.B1AF22A6C12C@llvm.org> Author: ggreif Date: Tue Mar 16 10:26:09 2010 New Revision: 98632 URL: http://llvm.org/viewvc/llvm-project?rev=98632&view=rev Log: add BranchInst tests Modified: llvm/trunk/unittests/VMCore/InstructionsTest.cpp Modified: llvm/trunk/unittests/VMCore/InstructionsTest.cpp URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/unittests/VMCore/InstructionsTest.cpp?rev=98632&r1=98631&r2=98632&view=diff ============================================================================== --- llvm/trunk/unittests/VMCore/InstructionsTest.cpp (original) +++ llvm/trunk/unittests/VMCore/InstructionsTest.cpp Tue Mar 16 10:26:09 2010 @@ -8,6 +8,7 @@ //===----------------------------------------------------------------------===// #include "llvm/Instructions.h" +#include "llvm/BasicBlock.h" #include "llvm/DerivedTypes.h" #include "llvm/LLVMContext.h" #include "gtest/gtest.h" @@ -20,11 +21,13 @@ // test for PR6589 const ReturnInst* r0 = ReturnInst::Create(C); + EXPECT_EQ(r0->getNumOperands(), 0U); EXPECT_EQ(r0->op_begin(), r0->op_end()); const IntegerType* Int1 = IntegerType::get(C, 1); Constant* One = ConstantInt::get(Int1, 1, true); const ReturnInst* r1 = ReturnInst::Create(C, One); + EXPECT_EQ(r1->getNumOperands(), 1U); User::const_op_iterator b(r1->op_begin()); EXPECT_NE(b, r1->op_end()); EXPECT_EQ(*b, One); @@ -37,5 +40,73 @@ delete r1; } +TEST(InstructionsTest, BranchInst) { + LLVMContext &C(getGlobalContext()); + + // Make a BasicBlocks + BasicBlock* bb0 = BasicBlock::Create(C); + BasicBlock* bb1 = BasicBlock::Create(C); + + // Mandatory BranchInst + const BranchInst* b0 = BranchInst::Create(bb0); + + // check num operands + EXPECT_EQ(b0->getNumOperands(), 1U); + + EXPECT_NE(b0->op_begin(), b0->op_end()); + + const IntegerType* Int1 = IntegerType::get(C, 1); + Constant* One = ConstantInt::get(Int1, 1, true); + + // Conditional BranchInst + BranchInst* b1 = BranchInst::Create(bb0, bb1, One); + + // check num operands + EXPECT_EQ(b1->getNumOperands(), 3U); + + User::const_op_iterator b(b1->op_begin()); + + // check COND + EXPECT_NE(b, b1->op_end()); + EXPECT_EQ(*b, One); + EXPECT_EQ(b1->getOperand(0), One); + ++b; + + // check ELSE + EXPECT_EQ(*b, bb1); + EXPECT_EQ(b1->getOperand(1), bb1); + ++b; + + // check THEN + EXPECT_EQ(*b, bb0); + EXPECT_EQ(b1->getOperand(2), bb0); + ++b; + + EXPECT_EQ(b, b1->op_end()); + + // shrink it + b1->setUnconditionalDest(bb1); + + // check num operands + EXPECT_EQ(b1->getNumOperands(), 1U); + + User::const_op_iterator c(b1->op_begin()); + EXPECT_NE(c, b1->op_end()); + + // check THEN + EXPECT_EQ(*c, bb1); + EXPECT_EQ(b1->getOperand(0), bb1); + ++c; + + EXPECT_EQ(c, b1->op_end()); + + // clean up + delete b0; + delete b1; + + delete bb0; + delete bb1; +} + } // end anonymous namespace } // end namespace llvm From aaronngray.lists at googlemail.com Tue Mar 16 10:37:14 2010 From: aaronngray.lists at googlemail.com (Aaron Gray) Date: Tue, 16 Mar 2010 15:37:14 +0000 Subject: [llvm-commits] Extract MachObjectWriter class to own header and code files In-Reply-To: <6a8523d61003160820r356df606p65747ce2c0f3c668@mail.gmail.com> References: <9719867c1003151006r720d53cewebc80de9802ed238@mail.gmail.com> <6a8523d61003151731v66234328qd84112c1d364a8a7@mail.gmail.com> <9719867c1003151801u5f4f4de2t1403eacc5eddf2b9@mail.gmail.com> <6a8523d61003160820r356df606p65747ce2c0f3c668@mail.gmail.com> Message-ID: <9719867c1003160837n61d300a4m453b981a4849649a@mail.gmail.com> On 16 March 2010 15:20, Daniel Dunbar wrote: > On Mon, Mar 15, 2010 at 6:01 PM, Aaron Gray > wrote: > > On 16 March 2010 00:31, Daniel Dunbar wrote: > >> > >> Hi Aaron, > >> > >> This has been on my list, but for the time being I find it convenient > >> to have all the code in the same place. I also want to factor out a > >> few more minor things before splitting in the target independent > >> assembler and the object file writer. > >> > >> Is this blocking work you are hoping to do? > > > > Hi Daniel, > > It would be good to get to the stage where I can work on the COFFWriter > and > > COFFStreamer. > > Ok. Do you mind waiting ~a week? > > > Basically I can wait but I thought a few file and class wise > normalizations > > would not go a miss :) > > Also I wanted to introduce a common ObjectWriter abstract class for > > MachObjectWriter, ELFObjectWriter, and COFFWriter, with Write and virtual > > WriteObject methods. > > Right. I have this stuff planned out in my head, along similar lines. > I'll try to get it in the next week but right now I wanted to get > x86_64 Mach-O support up, which gives two concrete implementations to > factor for. Work for you? Okay, thats great :) Aaron -------------- next part -------------- An HTML attachment was scrubbed... URL: http://lists.cs.uiuc.edu/pipermail/llvm-commits/attachments/20100316/ede822d6/attachment.html From daniel at zuster.org Tue Mar 16 10:53:02 2010 From: daniel at zuster.org (Daniel Dunbar) Date: Tue, 16 Mar 2010 15:53:02 -0000 Subject: [llvm-commits] [llvm] r98633 - /llvm/trunk/utils/NewNightlyTest.pl Message-ID: <20100316155302.600E92A6C12C@llvm.org> Author: ddunbar Date: Tue Mar 16 10:53:02 2010 New Revision: 98633 URL: http://llvm.org/viewvc/llvm-project?rev=98633&view=rev Log: NNT: Add -nouname option, so machine uniquing can occur across physical machines. Modified: llvm/trunk/utils/NewNightlyTest.pl Modified: llvm/trunk/utils/NewNightlyTest.pl URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/utils/NewNightlyTest.pl?rev=98633&r1=98632&r2=98633&view=diff ============================================================================== --- llvm/trunk/utils/NewNightlyTest.pl (original) +++ llvm/trunk/utils/NewNightlyTest.pl Tue Mar 16 10:53:02 2010 @@ -24,6 +24,7 @@ # IMPLEMENTED. # -nickname NAME The NAME argument specifieds the nickname this script # will submit to the nightlytest results repository. +# -nouname Don't include uname data (machine will be identified by nickname only). # -submit-server Specifies a server to submit the test results too. If this # option is not specified it defaults to # llvm.org. This is basically just the address of the @@ -220,6 +221,7 @@ $LLVMGCCPATH = $ARGV[0] . '/bin'; shift; next;} if (/^-noexternals$/) { $NOEXTERNALS = 1; next; } + if (/^-nouname$/) { $NOUNAME = 1; next; } if (/^-use-gmake/) { $MAKECMD = "gmake"; shift; next; } if (/^-extraflags/) { $CONFIGUREARGS .= " --with-extra-options=\'$ARGV[0]\'"; shift; next;} @@ -693,12 +695,21 @@ if ( $VERBOSE ) { print "PREPARING LOGS TO BE SENT TO SERVER\n"; } -$machine_data = "uname: ".`uname -a`. - "hardware: ".`uname -m`. - "os: ".`uname -sr`. - "name: ".`uname -n`. - "date: ".`date \"+20%y-%m-%d\"`. - "time: ".`date +\"%H:%M:%S\"`; +if ( ! $NOUNAME ) { + $machine_data = "uname: ".`uname -a`. + "hardware: ".`uname -m`. + "os: ".`uname -sr`. + "name: ".`uname -n`. + "date: ".`date \"+20%y-%m-%d\"`. + "time: ".`date +\"%H:%M:%S\"`; +} else { + $machine_data = "uname: (excluded)\n". + "hardware: ".`uname -m`. + "os: ".`uname -sr`. + "name: $nickname\n". + "date: ".`date \"+20%y-%m-%d\"`. + "time: ".`date +\"%H:%M:%S\"`; +} # Get gcc version. my $gcc_version_long = ""; From ggreif at gmail.com Tue Mar 16 10:53:58 2010 From: ggreif at gmail.com (Gabor Greif) Date: Tue, 16 Mar 2010 15:53:58 -0000 Subject: [llvm-commits] [llvm] r98634 - /llvm/trunk/unittests/VMCore/InstructionsTest.cpp Message-ID: <20100316155358.966292A6C12C@llvm.org> Author: ggreif Date: Tue Mar 16 10:53:58 2010 New Revision: 98634 URL: http://llvm.org/viewvc/llvm-project?rev=98634&view=rev Log: more BranchInst tests Modified: llvm/trunk/unittests/VMCore/InstructionsTest.cpp Modified: llvm/trunk/unittests/VMCore/InstructionsTest.cpp URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/unittests/VMCore/InstructionsTest.cpp?rev=98634&r1=98633&r2=98634&view=diff ============================================================================== --- llvm/trunk/unittests/VMCore/InstructionsTest.cpp (original) +++ llvm/trunk/unittests/VMCore/InstructionsTest.cpp Tue Mar 16 10:53:58 2010 @@ -50,10 +50,17 @@ // Mandatory BranchInst const BranchInst* b0 = BranchInst::Create(bb0); + EXPECT_TRUE(b0->isUnconditional()); + EXPECT_FALSE(b0->isConditional()); + EXPECT_EQ(b0->getNumSuccessors(), 1U); + // check num operands EXPECT_EQ(b0->getNumOperands(), 1U); EXPECT_NE(b0->op_begin(), b0->op_end()); + EXPECT_EQ(b0->op_begin() + 1, b0->op_end()); + + EXPECT_EQ(b0->op_begin() + 1, b0->op_end()); const IntegerType* Int1 = IntegerType::get(C, 1); Constant* One = ConstantInt::get(Int1, 1, true); @@ -61,6 +68,10 @@ // Conditional BranchInst BranchInst* b1 = BranchInst::Create(bb0, bb1, One); + EXPECT_FALSE(b1->isUnconditional()); + EXPECT_TRUE(b1->isConditional()); + EXPECT_EQ(b1->getNumSuccessors(), 2U); + // check num operands EXPECT_EQ(b1->getNumOperands(), 3U); @@ -70,16 +81,19 @@ EXPECT_NE(b, b1->op_end()); EXPECT_EQ(*b, One); EXPECT_EQ(b1->getOperand(0), One); + EXPECT_EQ(b1->getCondition(), One); ++b; // check ELSE EXPECT_EQ(*b, bb1); EXPECT_EQ(b1->getOperand(1), bb1); + EXPECT_EQ(b1->getSuccessor(1), bb1); ++b; // check THEN EXPECT_EQ(*b, bb0); EXPECT_EQ(b1->getOperand(2), bb0); + EXPECT_EQ(b1->getSuccessor(0), bb0); ++b; EXPECT_EQ(b, b1->op_end()); @@ -96,6 +110,7 @@ // check THEN EXPECT_EQ(*c, bb1); EXPECT_EQ(b1->getOperand(0), bb1); + EXPECT_EQ(b1->getSuccessor(0), bb1); ++c; EXPECT_EQ(c, b1->op_end()); From bob.wilson at apple.com Tue Mar 16 11:19:07 2010 From: bob.wilson at apple.com (Bob Wilson) Date: Tue, 16 Mar 2010 16:19:07 -0000 Subject: [llvm-commits] [llvm] r98635 - in /llvm/trunk: lib/Target/ARM/ARMAddressingModes.h lib/Target/ARM/AsmPrinter/ARMAsmPrinter.cpp lib/Target/ARM/AsmPrinter/ARMInstPrinter.cpp test/CodeGen/ARM/ifcvt5.ll test/CodeGen/ARM/ifcvt6.ll test/CodeGen/ARM/ifcvt7.ll test/CodeGen/ARM/ifcvt8.ll test/CodeGen/ARM/ldm.ll test/CodeGen/Thumb2/2009-10-15-ITBlockBranch.ll test/CodeGen/Thumb2/large-stack.ll Message-ID: <20100316161908.056662A6C12C@llvm.org> Author: bwilson Date: Tue Mar 16 11:19:07 2010 New Revision: 98635 URL: http://llvm.org/viewvc/llvm-project?rev=98635&view=rev Log: Stop using the old pre-UAL syntax for LDM/STM instruction suffixes. This does not move entirely to UAL syntax, since the default "increment after" suffix is empty but we still use "IA" for that. Modified: llvm/trunk/lib/Target/ARM/ARMAddressingModes.h llvm/trunk/lib/Target/ARM/AsmPrinter/ARMAsmPrinter.cpp llvm/trunk/lib/Target/ARM/AsmPrinter/ARMInstPrinter.cpp llvm/trunk/test/CodeGen/ARM/ifcvt5.ll llvm/trunk/test/CodeGen/ARM/ifcvt6.ll llvm/trunk/test/CodeGen/ARM/ifcvt7.ll llvm/trunk/test/CodeGen/ARM/ifcvt8.ll llvm/trunk/test/CodeGen/ARM/ldm.ll llvm/trunk/test/CodeGen/Thumb2/2009-10-15-ITBlockBranch.ll llvm/trunk/test/CodeGen/Thumb2/large-stack.ll Modified: llvm/trunk/lib/Target/ARM/ARMAddressingModes.h URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Target/ARM/ARMAddressingModes.h?rev=98635&r1=98634&r2=98635&view=diff ============================================================================== --- llvm/trunk/lib/Target/ARM/ARMAddressingModes.h (original) +++ llvm/trunk/lib/Target/ARM/ARMAddressingModes.h Tue Mar 16 11:19:07 2010 @@ -78,16 +78,6 @@ } } - static inline const char *getAMSubModeAltStr(AMSubMode Mode, bool isLD) { - switch (Mode) { - default: assert(0 && "Unknown addressing sub-mode!"); - case ARM_AM::ia: return isLD ? "fd" : "ea"; - case ARM_AM::ib: return isLD ? "ed" : "fa"; - case ARM_AM::da: return isLD ? "fa" : "ed"; - case ARM_AM::db: return isLD ? "ea" : "fd"; - } - } - /// rotr32 - Rotate a 32-bit unsigned value right by a specified # bits. /// static inline unsigned rotr32(unsigned Val, unsigned Amt) { Modified: llvm/trunk/lib/Target/ARM/AsmPrinter/ARMAsmPrinter.cpp URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Target/ARM/AsmPrinter/ARMAsmPrinter.cpp?rev=98635&r1=98634&r2=98635&view=diff ============================================================================== --- llvm/trunk/lib/Target/ARM/AsmPrinter/ARMAsmPrinter.cpp (original) +++ llvm/trunk/lib/Target/ARM/AsmPrinter/ARMAsmPrinter.cpp Tue Mar 16 11:19:07 2010 @@ -518,17 +518,7 @@ const MachineOperand &MO2 = MI->getOperand(Op+1); ARM_AM::AMSubMode Mode = ARM_AM::getAM4SubMode(MO2.getImm()); if (Modifier && strcmp(Modifier, "submode") == 0) { - if (MO1.getReg() == ARM::SP) { - // FIXME - bool isLDM = (MI->getOpcode() == ARM::LDM || - MI->getOpcode() == ARM::LDM_UPD || - MI->getOpcode() == ARM::LDM_RET || - MI->getOpcode() == ARM::t2LDM || - MI->getOpcode() == ARM::t2LDM_UPD || - MI->getOpcode() == ARM::t2LDM_RET); - O << ARM_AM::getAMSubModeAltStr(Mode, isLDM); - } else - O << ARM_AM::getAMSubModeStr(Mode); + O << ARM_AM::getAMSubModeStr(Mode); } else if (Modifier && strcmp(Modifier, "wide") == 0) { ARM_AM::AMSubMode Mode = ARM_AM::getAM4SubMode(MO2.getImm()); if (Mode == ARM_AM::ia) Modified: llvm/trunk/lib/Target/ARM/AsmPrinter/ARMInstPrinter.cpp URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Target/ARM/AsmPrinter/ARMInstPrinter.cpp?rev=98635&r1=98634&r2=98635&view=diff ============================================================================== --- llvm/trunk/lib/Target/ARM/AsmPrinter/ARMInstPrinter.cpp (original) +++ llvm/trunk/lib/Target/ARM/AsmPrinter/ARMInstPrinter.cpp Tue Mar 16 11:19:07 2010 @@ -226,15 +226,7 @@ const MCOperand &MO2 = MI->getOperand(OpNum+1); ARM_AM::AMSubMode Mode = ARM_AM::getAM4SubMode(MO2.getImm()); if (Modifier && strcmp(Modifier, "submode") == 0) { - if (MO1.getReg() == ARM::SP) { - // FIXME - bool isLDM = (MI->getOpcode() == ARM::LDM || - MI->getOpcode() == ARM::LDM_RET || - MI->getOpcode() == ARM::t2LDM || - MI->getOpcode() == ARM::t2LDM_RET); - O << ARM_AM::getAMSubModeAltStr(Mode, isLDM); - } else - O << ARM_AM::getAMSubModeStr(Mode); + O << ARM_AM::getAMSubModeStr(Mode); } else if (Modifier && strcmp(Modifier, "wide") == 0) { ARM_AM::AMSubMode Mode = ARM_AM::getAM4SubMode(MO2.getImm()); if (Mode == ARM_AM::ia) Modified: llvm/trunk/test/CodeGen/ARM/ifcvt5.ll URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/CodeGen/ARM/ifcvt5.ll?rev=98635&r1=98634&r2=98635&view=diff ============================================================================== --- llvm/trunk/test/CodeGen/ARM/ifcvt5.ll (original) +++ llvm/trunk/test/CodeGen/ARM/ifcvt5.ll Tue Mar 16 11:19:07 2010 @@ -11,7 +11,7 @@ define void @t1(i32 %a, i32 %b) { ; CHECK: t1: -; CHECK: ldmfdlt sp!, {r7, pc} +; CHECK: ldmialt sp!, {r7, pc} entry: %tmp1 = icmp sgt i32 %a, 10 ; [#uses=1] br i1 %tmp1, label %cond_true, label %UnifiedReturnBlock Modified: llvm/trunk/test/CodeGen/ARM/ifcvt6.ll URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/CodeGen/ARM/ifcvt6.ll?rev=98635&r1=98634&r2=98635&view=diff ============================================================================== --- llvm/trunk/test/CodeGen/ARM/ifcvt6.ll (original) +++ llvm/trunk/test/CodeGen/ARM/ifcvt6.ll Tue Mar 16 11:19:07 2010 @@ -1,7 +1,7 @@ ; RUN: llc < %s -march=arm -mtriple=arm-apple-darwin | \ ; RUN: grep cmpne | count 1 ; RUN: llc < %s -march=arm -mtriple=arm-apple-darwin | \ -; RUN: grep ldmfdhi | count 1 +; RUN: grep ldmiahi | count 1 define void @foo(i32 %X, i32 %Y) { entry: Modified: llvm/trunk/test/CodeGen/ARM/ifcvt7.ll URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/CodeGen/ARM/ifcvt7.ll?rev=98635&r1=98634&r2=98635&view=diff ============================================================================== --- llvm/trunk/test/CodeGen/ARM/ifcvt7.ll (original) +++ llvm/trunk/test/CodeGen/ARM/ifcvt7.ll Tue Mar 16 11:19:07 2010 @@ -3,7 +3,7 @@ ; RUN: llc < %s -march=arm -mtriple=arm-apple-darwin | \ ; RUN: grep moveq | count 1 ; RUN: llc < %s -march=arm -mtriple=arm-apple-darwin | \ -; RUN: grep ldmfdeq | count 1 +; RUN: grep ldmiaeq | count 1 ; FIXME: Need post-ifcvt branch folding to get rid of the extra br at end of BB1. %struct.quad_struct = type { i32, i32, %struct.quad_struct*, %struct.quad_struct*, %struct.quad_struct*, %struct.quad_struct*, %struct.quad_struct* } Modified: llvm/trunk/test/CodeGen/ARM/ifcvt8.ll URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/CodeGen/ARM/ifcvt8.ll?rev=98635&r1=98634&r2=98635&view=diff ============================================================================== --- llvm/trunk/test/CodeGen/ARM/ifcvt8.ll (original) +++ llvm/trunk/test/CodeGen/ARM/ifcvt8.ll Tue Mar 16 11:19:07 2010 @@ -1,5 +1,5 @@ ; RUN: llc < %s -march=arm -mtriple=arm-apple-darwin | \ -; RUN: grep ldmfdne | count 1 +; RUN: grep ldmiane | count 1 %struct.SString = type { i8*, i32, i32 } Modified: llvm/trunk/test/CodeGen/ARM/ldm.ll URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/CodeGen/ARM/ldm.ll?rev=98635&r1=98634&r2=98635&view=diff ============================================================================== --- llvm/trunk/test/CodeGen/ARM/ldm.ll (original) +++ llvm/trunk/test/CodeGen/ARM/ldm.ll Tue Mar 16 11:19:07 2010 @@ -24,7 +24,7 @@ define i32 @t3() { ; CHECK: t3: ; CHECK: ldmib -; CHECK: ldmfd sp! +; CHECK: ldmia sp! %tmp = load i32* getelementptr ([0 x i32]* @X, i32 0, i32 1) ; [#uses=1] %tmp3 = load i32* getelementptr ([0 x i32]* @X, i32 0, i32 2) ; [#uses=1] %tmp5 = load i32* getelementptr ([0 x i32]* @X, i32 0, i32 3) ; [#uses=1] Modified: llvm/trunk/test/CodeGen/Thumb2/2009-10-15-ITBlockBranch.ll URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/CodeGen/Thumb2/2009-10-15-ITBlockBranch.ll?rev=98635&r1=98634&r2=98635&view=diff ============================================================================== --- llvm/trunk/test/CodeGen/Thumb2/2009-10-15-ITBlockBranch.ll (original) +++ llvm/trunk/test/CodeGen/Thumb2/2009-10-15-ITBlockBranch.ll Tue Mar 16 11:19:07 2010 @@ -12,10 +12,10 @@ define weak arm_aapcs_vfpcc i32 @_ZNKSs7compareERKSs(%"struct.std::basic_string,std::allocator >"* %this, %"struct.std::basic_string,std::allocator >"* %__str) { ; CHECK: _ZNKSs7compareERKSs: ; CHECK: it ne -; CHECK-NEXT: ldmfdne.w +; CHECK-NEXT: ldmiane.w ; CHECK-NEXT: itt eq ; CHECK-NEXT: subeq.w -; CHECK-NEXT: ldmfdeq.w +; CHECK-NEXT: ldmiaeq.w entry: %0 = tail call arm_aapcs_vfpcc i32 @_ZNKSs4sizeEv(%"struct.std::basic_string,std::allocator >"* %this) ; [#uses=3] %1 = tail call arm_aapcs_vfpcc i32 @_ZNKSs4sizeEv(%"struct.std::basic_string,std::allocator >"* %__str) ; [#uses=3] Modified: llvm/trunk/test/CodeGen/Thumb2/large-stack.ll URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/CodeGen/Thumb2/large-stack.ll?rev=98635&r1=98634&r2=98635&view=diff ============================================================================== --- llvm/trunk/test/CodeGen/Thumb2/large-stack.ll (original) +++ llvm/trunk/test/CodeGen/Thumb2/large-stack.ll Tue Mar 16 11:19:07 2010 @@ -27,7 +27,7 @@ ; DARWIN: sub.w sp, sp, #805306368 ; DARWIN: sub sp, #20 ; LINUX: test3: -; LINUX: stmfd sp!, {r4, r7, r11, lr} +; LINUX: stmdb sp!, {r4, r7, r11, lr} ; LINUX: sub.w sp, sp, #805306368 ; LINUX: sub sp, #16 %retval = alloca i32, align 4 From johnny.chen at apple.com Tue Mar 16 11:36:54 2010 From: johnny.chen at apple.com (Johnny Chen) Date: Tue, 16 Mar 2010 16:36:54 -0000 Subject: [llvm-commits] [llvm] r98637 - in /llvm/trunk: ./ lib/Target/ARM/ lib/Target/ARM/AsmPrinter/ lib/Target/ARM/Disassembler/ test/CodeGen/ARM/ test/CodeGen/Thumb2/ utils/TableGen/ Message-ID: <20100316163655.029872A6C12C@llvm.org> Author: johnny Date: Tue Mar 16 11:36:54 2010 New Revision: 98637 URL: http://llvm.org/viewvc/llvm-project?rev=98637&view=rev Log: Initial ARM/Thumb disassembler check-in. It consists of a tablgen backend (RISCDisassemblerEmitter) which emits the decoder functions for ARM and Thumb, and the disassembler core which invokes the decoder function and builds up the MCInst based on the decoded Opcode. Added sub-formats to the NeonI/NeonXI instructions to further refine the NEONFrm instructions to help disassembly. We also changed the output of the addressing modes to omit the '+' from the assembler syntax #+/- or +/-. See, for example, A8.6.57/58/60. And modified test cases to not expect '+' in +reg or #+num. For example, ; CHECK: ldr.w r9, [r7, #28] Added: llvm/trunk/lib/Target/ARM/Disassembler/ llvm/trunk/lib/Target/ARM/Disassembler/ARMDisassembler.cpp llvm/trunk/lib/Target/ARM/Disassembler/ARMDisassembler.h llvm/trunk/lib/Target/ARM/Disassembler/ARMDisassemblerCore.cpp llvm/trunk/lib/Target/ARM/Disassembler/ARMDisassemblerCore.h llvm/trunk/lib/Target/ARM/Disassembler/Makefile llvm/trunk/lib/Target/ARM/Disassembler/ThumbDisassemblerCore.cpp.inc llvm/trunk/utils/TableGen/RISCDisassemblerEmitter.cpp llvm/trunk/utils/TableGen/RISCDisassemblerEmitter.h Modified: llvm/trunk/Makefile.rules llvm/trunk/lib/Target/ARM/ARMAddressingModes.h llvm/trunk/lib/Target/ARM/ARMInstrFormats.td llvm/trunk/lib/Target/ARM/ARMInstrNEON.td llvm/trunk/lib/Target/ARM/AsmPrinter/ARMAsmPrinter.cpp llvm/trunk/lib/Target/ARM/AsmPrinter/ARMInstPrinter.cpp llvm/trunk/lib/Target/ARM/AsmPrinter/ARMInstPrinter.h llvm/trunk/lib/Target/ARM/Makefile llvm/trunk/lib/Target/ARM/Thumb2ITBlockPass.cpp llvm/trunk/test/CodeGen/ARM/2009-10-27-double-align.ll llvm/trunk/test/CodeGen/ARM/2009-10-30.ll llvm/trunk/test/CodeGen/ARM/arm-negative-stride.ll llvm/trunk/test/CodeGen/ARM/globals.ll llvm/trunk/test/CodeGen/ARM/ldrd.ll llvm/trunk/test/CodeGen/ARM/str_pre-2.ll llvm/trunk/test/CodeGen/ARM/tls2.ll llvm/trunk/test/CodeGen/Thumb2/ldr-str-imm12.ll llvm/trunk/test/CodeGen/Thumb2/thumb2-ldr.ll llvm/trunk/test/CodeGen/Thumb2/thumb2-ldrh.ll llvm/trunk/test/CodeGen/Thumb2/thumb2-str.ll llvm/trunk/test/CodeGen/Thumb2/thumb2-str_pre.ll llvm/trunk/test/CodeGen/Thumb2/thumb2-strb.ll llvm/trunk/test/CodeGen/Thumb2/thumb2-strh.ll llvm/trunk/utils/TableGen/DisassemblerEmitter.cpp llvm/trunk/utils/TableGen/TableGen.cpp Modified: llvm/trunk/Makefile.rules URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/Makefile.rules?rev=98637&r1=98636&r2=98637&view=diff ============================================================================== --- llvm/trunk/Makefile.rules (original) +++ llvm/trunk/Makefile.rules Tue Mar 16 11:36:54 2010 @@ -1614,6 +1614,11 @@ $(Echo) "Building $(> 8) * 2; } + /// getSOImmValOneRotate - Try to handle Imm with an immediate shifter + /// operand, computing the rotate amount to use. If this immediate value + /// cannot be handled with a single shifter-op, return 0. + static inline unsigned getSOImmValOneRotate(unsigned Imm) { + // A5.2.4 Constants with multiple encodings + // The lowest unsigned value of rotation wins! + for (unsigned R = 1; R <= 15; ++R) + if ((Imm & rotr32(~255U, 2*R)) == 0) + return 2*R; + + // Failed to find a suitable rotate amount. + return 0; + } + /// getSOImmValRotate - Try to handle Imm with an immediate shifter operand, /// computing the rotate amount to use. If this immediate value cannot be /// handled with a single shifter-op, determine a good rotate amount that will @@ -179,7 +197,7 @@ // of zero. if ((Arg & ~255U) == 0) return Arg; - unsigned RotAmt = getSOImmValRotate(Arg); + unsigned RotAmt = getSOImmValOneRotate(Arg); // If this cannot be handled with a single shifter_op, bail out. if (rotr32(~255U, RotAmt) & Arg) Modified: llvm/trunk/lib/Target/ARM/ARMInstrFormats.td URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Target/ARM/ARMInstrFormats.td?rev=98637&r1=98636&r2=98637&view=diff ============================================================================== --- llvm/trunk/lib/Target/ARM/ARMInstrFormats.td (original) +++ llvm/trunk/lib/Target/ARM/ARMInstrFormats.td Tue Mar 16 11:36:54 2010 @@ -1464,6 +1464,29 @@ // ARM NEON Instruction templates. // +// NSFormat specifies further details of a NEON instruction. This is used by +// the disassembler to classify NEONFrm instructions for disassembly purpose. +class NSFormat val> { + bits<5> Value = val; +} +def NSFormatNone : NSFormat<0>; +def VLDSTLaneFrm : NSFormat<1>; +def VLDSTLaneDblFrm : NSFormat<2>; +def VLDSTRQFrm : NSFormat<3>; +def NVdImmFrm : NSFormat<4>; +def NVdVmImmFrm : NSFormat<5>; +def NVdVmImmVCVTFrm : NSFormat<6>; +def NVdVmImmVDupLaneFrm : NSFormat<7>; +def NVdVmImmVSHLLFrm : NSFormat<8>; +def NVectorShuffleFrm : NSFormat<9>; +def NVectorShiftFrm : NSFormat<10>; +def NVectorShift2Frm : NSFormat<11>; +def NVdVnVmImmFrm : NSFormat<12>; +def NVdVnVmImmVectorShiftFrm : NSFormat<13>; +def NVdVnVmImmVectorExtractFrm : NSFormat<14>; +def NVdVnVmImmMulScalarFrm : NSFormat<15>; +def VTBLFrm : NSFormat<16>; + class NeonI pattern> : InstARM { @@ -1474,6 +1497,8 @@ !strconcat("\t", asm)); let Pattern = pattern; list Predicates = [HasNEON]; + NSFormat NSF = NSFormatNone; // For disassembly. + bits<5> NSForm = NSFormatNone.Value; // For disassembly. } // Same as NeonI except it does not have a "data type" specifier. @@ -1485,6 +1510,8 @@ let AsmString = !strconcat(!strconcat(opc, "${p}"), !strconcat("\t", asm)); let Pattern = pattern; list Predicates = [HasNEON]; + NSFormat NSF = NSFormatNone; // For disassembly. + bits<5> NSForm = NSFormatNone.Value; // For disassembly. } class NI pattern> : NeonXI { + let NSF = VLDSTRQFrm; // For disassembly. + let NSForm = VLDSTRQFrm.Value; // For disassembly. } class NLdSt op21_20, bits<4> op11_8, bits<4> op7_4, @@ -1509,6 +1538,8 @@ let Inst{21-20} = op21_20; let Inst{11-8} = op11_8; let Inst{7-4} = op7_4; + let NSF = VLDSTLaneFrm; // For disassembly. + let NSForm = VLDSTLaneFrm.Value; // For disassembly. } class NDataI op7_4, string OpcodeStr, string Dt> : NLdSt<0,0b10,0b1001,op7_4, (outs DPR:$dst1, DPR:$dst2), (ins addrmode6:$addr), IIC_VLD2, - OpcodeStr, Dt, "\\{$dst1, $dst2\\}, $addr", "", []>; + OpcodeStr, Dt, "\\{$dst1, $dst2\\}, $addr", "", []> { + let NSF = VLDSTLaneDblFrm; // For disassembly. + let NSForm = VLDSTLaneDblFrm.Value; // For disassembly. +} def VLD2d8D : VLD2Ddbl<0b0000, "vld2", "8">; def VLD2d16D : VLD2Ddbl<0b0100, "vld2", "16">; @@ -228,7 +231,10 @@ : NLdSt<0,0b10,0b0101,op7_4, (outs DPR:$dst1, DPR:$dst2, DPR:$dst3, GPR:$wb), (ins addrmode6:$addr), IIC_VLD3, OpcodeStr, Dt, "\\{$dst1, $dst2, $dst3\\}, $addr", - "$addr.addr = $wb", []>; + "$addr.addr = $wb", []> { + let NSF = VLDSTLaneDblFrm; // For disassembly. + let NSForm = VLDSTLaneDblFrm.Value; // For disassembly. +} def VLD3d8 : VLD3D<0b0000, "vld3", "8">; def VLD3d16 : VLD3D<0b0100, "vld3", "16">; @@ -260,7 +266,10 @@ (outs DPR:$dst1, DPR:$dst2, DPR:$dst3, DPR:$dst4, GPR:$wb), (ins addrmode6:$addr), IIC_VLD4, OpcodeStr, Dt, "\\{$dst1, $dst2, $dst3, $dst4\\}, $addr", - "$addr.addr = $wb", []>; + "$addr.addr = $wb", []> { + let NSF = VLDSTLaneDblFrm; // For disassembly. + let NSForm = VLDSTLaneDblFrm.Value; // For disassembly. +} def VLD4d8 : VLD4D<0b0000, "vld4", "8">; def VLD4d16 : VLD4D<0b0100, "vld4", "16">; @@ -297,12 +306,28 @@ def VLD2LNd32 : VLD2LN<0b1001, "vld2", "32"> { let Inst{6} = 0; } // vld2 to double-spaced even registers. -def VLD2LNq16a: VLD2LN<0b0101, "vld2", "16"> { let Inst{5} = 1; } -def VLD2LNq32a: VLD2LN<0b1001, "vld2", "32"> { let Inst{6} = 1; } +def VLD2LNq16a: VLD2LN<0b0101, "vld2", "16"> { + let Inst{5} = 1; + let NSF = VLDSTLaneDblFrm; // For disassembly. + let NSForm = VLDSTLaneDblFrm.Value; // For disassembly. +} +def VLD2LNq32a: VLD2LN<0b1001, "vld2", "32"> { + let Inst{6} = 1; + let NSF = VLDSTLaneDblFrm; // For disassembly. + let NSForm = VLDSTLaneDblFrm.Value; // For disassembly. +} // vld2 to double-spaced odd registers. -def VLD2LNq16b: VLD2LN<0b0101, "vld2", "16"> { let Inst{5} = 1; } -def VLD2LNq32b: VLD2LN<0b1001, "vld2", "32"> { let Inst{6} = 1; } +def VLD2LNq16b: VLD2LN<0b0101, "vld2", "16"> { + let Inst{5} = 1; + let NSF = VLDSTLaneDblFrm; // For disassembly. + let NSForm = VLDSTLaneDblFrm.Value; // For disassembly. +} +def VLD2LNq32b: VLD2LN<0b1001, "vld2", "32"> { + let Inst{6} = 1; + let NSF = VLDSTLaneDblFrm; // For disassembly. + let NSForm = VLDSTLaneDblFrm.Value; // For disassembly. +} // VLD3LN : Vector Load (single 3-element structure to one lane) class VLD3LN op11_8, string OpcodeStr, string Dt> @@ -318,7 +343,11 @@ def VLD3LNd32 : VLD3LN<0b1010, "vld3", "32"> { let Inst{6-4} = 0b000; } // vld3 to double-spaced even registers. -def VLD3LNq16a: VLD3LN<0b0110, "vld3", "16"> { let Inst{5-4} = 0b10; } +def VLD3LNq16a: VLD3LN<0b0110, "vld3", "16"> { + let Inst{5-4} = 0b10; + let NSF = VLDSTLaneDblFrm; // For disassembly. + let NSForm = VLDSTLaneDblFrm.Value; // For disassembly. +} def VLD3LNq32a: VLD3LN<0b1010, "vld3", "32"> { let Inst{6-4} = 0b100; } // vld3 to double-spaced odd registers. @@ -340,12 +369,28 @@ def VLD4LNd32 : VLD4LN<0b1011, "vld4", "32"> { let Inst{6} = 0; } // vld4 to double-spaced even registers. -def VLD4LNq16a: VLD4LN<0b0111, "vld4", "16"> { let Inst{5} = 1; } -def VLD4LNq32a: VLD4LN<0b1011, "vld4", "32"> { let Inst{6} = 1; } +def VLD4LNq16a: VLD4LN<0b0111, "vld4", "16"> { + let Inst{5} = 1; + let NSF = VLDSTLaneDblFrm; // For disassembly. + let NSForm = VLDSTLaneDblFrm.Value; // For disassembly. +} +def VLD4LNq32a: VLD4LN<0b1011, "vld4", "32"> { + let Inst{6} = 1; + let NSF = VLDSTLaneDblFrm; // For disassembly. + let NSForm = VLDSTLaneDblFrm.Value; // For disassembly. +} // vld4 to double-spaced odd registers. -def VLD4LNq16b: VLD4LN<0b0111, "vld4", "16"> { let Inst{5} = 1; } -def VLD4LNq32b: VLD4LN<0b1011, "vld4", "32"> { let Inst{6} = 1; } +def VLD4LNq16b: VLD4LN<0b0111, "vld4", "16"> { + let Inst{5} = 1; + let NSF = VLDSTLaneDblFrm; // For disassembly. + let NSForm = VLDSTLaneDblFrm.Value; // For disassembly. +} +def VLD4LNq32b: VLD4LN<0b1011, "vld4", "32"> { + let Inst{6} = 1; + let NSF = VLDSTLaneDblFrm; // For disassembly. + let NSForm = VLDSTLaneDblFrm.Value; // For disassembly. +} // VLD1DUP : Vector Load (single element to all lanes) // VLD2DUP : Vector Load (single 2-element structure to all lanes) @@ -433,7 +478,10 @@ class VST2Ddbl op7_4, string OpcodeStr, string Dt> : NLdSt<0, 0b00, 0b1001, op7_4, (outs), (ins addrmode6:$addr, DPR:$src1, DPR:$src2), IIC_VST, - OpcodeStr, Dt, "\\{$src1, $src2\\}, $addr", "", []>; + OpcodeStr, Dt, "\\{$src1, $src2\\}, $addr", "", []> { + let NSF = VLDSTLaneDblFrm; // For disassembly. + let NSForm = VLDSTLaneDblFrm.Value; // For disassembly. +} def VST2d8D : VST2Ddbl<0b0000, "vst2", "8">; def VST2d16D : VST2Ddbl<0b0100, "vst2", "16">; @@ -448,7 +496,10 @@ : NLdSt<0,0b00,0b0101,op7_4, (outs GPR:$wb), (ins addrmode6:$addr, DPR:$src1, DPR:$src2, DPR:$src3), IIC_VST, OpcodeStr, Dt, "\\{$src1, $src2, $src3\\}, $addr", - "$addr.addr = $wb", []>; + "$addr.addr = $wb", []> { + let NSF = VLDSTLaneDblFrm; // For disassembly. + let NSForm = VLDSTLaneDblFrm.Value; // For disassembly. +} def VST3d8 : VST3D<0b0000, "vst3", "8">; def VST3d16 : VST3D<0b0100, "vst3", "16">; @@ -478,7 +529,10 @@ : NLdSt<0,0b00,0b0001,op7_4, (outs GPR:$wb), (ins addrmode6:$addr, DPR:$src1, DPR:$src2, DPR:$src3, DPR:$src4), IIC_VST, OpcodeStr, Dt, "\\{$src1, $src2, $src3, $src4\\}, $addr", - "$addr.addr = $wb", []>; + "$addr.addr = $wb", []> { + let NSF = VLDSTLaneDblFrm; // For disassembly. + let NSForm = VLDSTLaneDblFrm.Value; // For disassembly. +} def VST4d8 : VST4D<0b0000, "vst4", "8">; def VST4d16 : VST4D<0b0100, "vst4", "16">; @@ -515,12 +569,28 @@ def VST2LNd32 : VST2LN<0b1001, "vst2", "32"> { let Inst{6} = 0; } // vst2 to double-spaced even registers. -def VST2LNq16a: VST2LN<0b0101, "vst2", "16"> { let Inst{5} = 1; } -def VST2LNq32a: VST2LN<0b1001, "vst2", "32"> { let Inst{6} = 1; } +def VST2LNq16a: VST2LN<0b0101, "vst2", "16"> { + let Inst{5} = 1; + let NSF = VLDSTLaneDblFrm; // For disassembly. + let NSForm = VLDSTLaneDblFrm.Value; // For disassembly. +} +def VST2LNq32a: VST2LN<0b1001, "vst2", "32"> { + let Inst{6} = 1; + let NSF = VLDSTLaneDblFrm; // For disassembly. + let NSForm = VLDSTLaneDblFrm.Value; // For disassembly. +} // vst2 to double-spaced odd registers. -def VST2LNq16b: VST2LN<0b0101, "vst2", "16"> { let Inst{5} = 1; } -def VST2LNq32b: VST2LN<0b1001, "vst2", "32"> { let Inst{6} = 1; } +def VST2LNq16b: VST2LN<0b0101, "vst2", "16"> { + let Inst{5} = 1; + let NSF = VLDSTLaneDblFrm; // For disassembly. + let NSForm = VLDSTLaneDblFrm.Value; // For disassembly. +} +def VST2LNq32b: VST2LN<0b1001, "vst2", "32"> { + let Inst{6} = 1; + let NSF = VLDSTLaneDblFrm; // For disassembly. + let NSForm = VLDSTLaneDblFrm.Value; // For disassembly. +} // VST3LN : Vector Store (single 3-element structure from one lane) class VST3LN op11_8, string OpcodeStr, string Dt> @@ -535,12 +605,28 @@ def VST3LNd32 : VST3LN<0b1010, "vst3", "32"> { let Inst{6-4} = 0b000; } // vst3 to double-spaced even registers. -def VST3LNq16a: VST3LN<0b0110, "vst3", "16"> { let Inst{5-4} = 0b10; } -def VST3LNq32a: VST3LN<0b1010, "vst3", "32"> { let Inst{6-4} = 0b100; } +def VST3LNq16a: VST3LN<0b0110, "vst3", "16"> { + let Inst{5-4} = 0b10; + let NSF = VLDSTLaneDblFrm; // For disassembly. + let NSForm = VLDSTLaneDblFrm.Value; // For disassembly. +} +def VST3LNq32a: VST3LN<0b1010, "vst3", "32"> { + let Inst{6-4} = 0b100; + let NSF = VLDSTLaneDblFrm; // For disassembly. + let NSForm = VLDSTLaneDblFrm.Value; // For disassembly. +} // vst3 to double-spaced odd registers. -def VST3LNq16b: VST3LN<0b0110, "vst3", "16"> { let Inst{5-4} = 0b10; } -def VST3LNq32b: VST3LN<0b1010, "vst3", "32"> { let Inst{6-4} = 0b100; } +def VST3LNq16b: VST3LN<0b0110, "vst3", "16"> { + let Inst{5-4} = 0b10; + let NSF = VLDSTLaneDblFrm; // For disassembly. + let NSForm = VLDSTLaneDblFrm.Value; // For disassembly. +} +def VST3LNq32b: VST3LN<0b1010, "vst3", "32"> { + let Inst{6-4} = 0b100; + let NSF = VLDSTLaneDblFrm; // For disassembly. + let NSForm = VLDSTLaneDblFrm.Value; // For disassembly. +} // VST4LN : Vector Store (single 4-element structure from one lane) class VST4LN op11_8, string OpcodeStr, string Dt> @@ -556,12 +642,28 @@ def VST4LNd32 : VST4LN<0b1011, "vst4", "32"> { let Inst{6} = 0; } // vst4 to double-spaced even registers. -def VST4LNq16a: VST4LN<0b0111, "vst4", "16"> { let Inst{5} = 1; } -def VST4LNq32a: VST4LN<0b1011, "vst4", "32"> { let Inst{6} = 1; } +def VST4LNq16a: VST4LN<0b0111, "vst4", "16"> { + let Inst{5} = 1; + let NSF = VLDSTLaneDblFrm; // For disassembly. + let NSForm = VLDSTLaneDblFrm.Value; // For disassembly. +} +def VST4LNq32a: VST4LN<0b1011, "vst4", "32"> { + let Inst{6} = 1; + let NSF = VLDSTLaneDblFrm; // For disassembly. + let NSForm = VLDSTLaneDblFrm.Value; // For disassembly. +} // vst4 to double-spaced odd registers. -def VST4LNq16b: VST4LN<0b0111, "vst4", "16"> { let Inst{5} = 1; } -def VST4LNq32b: VST4LN<0b1011, "vst4", "32"> { let Inst{6} = 1; } +def VST4LNq16b: VST4LN<0b0111, "vst4", "16"> { + let Inst{5} = 1; + let NSF = VLDSTLaneDblFrm; // For disassembly. + let NSForm = VLDSTLaneDblFrm.Value; // For disassembly. +} +def VST4LNq32b: VST4LN<0b1011, "vst4", "32"> { + let Inst{6} = 1; + let NSF = VLDSTLaneDblFrm; // For disassembly. + let NSForm = VLDSTLaneDblFrm.Value; // For disassembly. +} } // mayStore = 1, hasExtraSrcRegAllocReq = 1 @@ -668,12 +770,18 @@ : N2V<0b11, 0b11, op19_18, 0b10, op11_7, 0, 0, (outs DPR:$dst1, DPR:$dst2), (ins DPR:$src1, DPR:$src2), IIC_VPERMD, OpcodeStr, Dt, "$dst1, $dst2", - "$src1 = $dst1, $src2 = $dst2", []>; + "$src1 = $dst1, $src2 = $dst2", []> { + let NSF = NVectorShuffleFrm; // For disassembly. + let NSForm = NVectorShuffleFrm.Value; // For disassembly. +} class N2VQShuffle op19_18, bits<5> op11_7, InstrItinClass itin, string OpcodeStr, string Dt> : N2V<0b11, 0b11, op19_18, 0b10, op11_7, 1, 0, (outs QPR:$dst1, QPR:$dst2), (ins QPR:$src1, QPR:$src2), itin, OpcodeStr, Dt, "$dst1, $dst2", - "$src1 = $dst1, $src2 = $dst2", []>; + "$src1 = $dst1, $src2 = $dst2", []> { + let NSF = NVectorShuffleFrm; // For disassembly. + let NSForm = NVectorShuffleFrm.Value; // For disassembly. +} // Basic 3-register operations: single-, double- and quad-register. class N3VS op21_20, bits<4> op11_8, bit op4, @@ -715,6 +823,8 @@ (Ty (ShOp (Ty DPR:$src1), (Ty (NEONvduplane (Ty DPR_VFP2:$src2), imm:$lane)))))]>{ let isCommutable = 0; + let NSF = NVdVnVmImmMulScalarFrm; // For disassembly. + let NSForm = NVdVnVmImmMulScalarFrm.Value; // For disassembly. } class N3VDSL16 op21_20, bits<4> op11_8, string OpcodeStr, string Dt, ValueType Ty, SDNode ShOp> @@ -725,6 +835,8 @@ (Ty (ShOp (Ty DPR:$src1), (Ty (NEONvduplane (Ty DPR_8:$src2), imm:$lane)))))]> { let isCommutable = 0; + let NSF = NVdVnVmImmMulScalarFrm; // For disassembly. + let NSForm = NVdVnVmImmMulScalarFrm.Value; // For disassembly. } class N3VQ op21_20, bits<4> op11_8, bit op4, @@ -756,6 +868,8 @@ (ResTy (NEONvduplane (OpTy DPR_VFP2:$src2), imm:$lane)))))]> { let isCommutable = 0; + let NSF = NVdVnVmImmMulScalarFrm; // For disassembly. + let NSForm = NVdVnVmImmMulScalarFrm.Value; // For disassembly. } class N3VQSL16 op21_20, bits<4> op11_8, string OpcodeStr, string Dt, ValueType ResTy, ValueType OpTy, SDNode ShOp> @@ -767,6 +881,8 @@ (ResTy (NEONvduplane (OpTy DPR_8:$src2), imm:$lane)))))]> { let isCommutable = 0; + let NSF = NVdVnVmImmMulScalarFrm; // For disassembly. + let NSForm = NVdVnVmImmMulScalarFrm.Value; // For disassembly. } // Basic 3-register intrinsics, both double- and quad-register. @@ -789,6 +905,8 @@ (Ty (NEONvduplane (Ty DPR_VFP2:$src2), imm:$lane)))))]> { let isCommutable = 0; + let NSF = NVdVnVmImmMulScalarFrm; // For disassembly. + let NSForm = NVdVnVmImmMulScalarFrm.Value; // For disassembly. } class N3VDIntSL16 op21_20, bits<4> op11_8, InstrItinClass itin, string OpcodeStr, string Dt, ValueType Ty, Intrinsic IntOp> @@ -800,6 +918,8 @@ (Ty (NEONvduplane (Ty DPR_8:$src2), imm:$lane)))))]> { let isCommutable = 0; + let NSF = NVdVnVmImmMulScalarFrm; // For disassembly. + let NSForm = NVdVnVmImmMulScalarFrm.Value; // For disassembly. } class N3VQInt op21_20, bits<4> op11_8, bit op4, @@ -822,6 +942,8 @@ (ResTy (NEONvduplane (OpTy DPR_VFP2:$src2), imm:$lane)))))]> { let isCommutable = 0; + let NSF = NVdVnVmImmMulScalarFrm; // For disassembly. + let NSForm = NVdVnVmImmMulScalarFrm.Value; // For disassembly. } class N3VQIntSL16 op21_20, bits<4> op11_8, InstrItinClass itin, string OpcodeStr, string Dt, @@ -834,6 +956,8 @@ (ResTy (NEONvduplane (OpTy DPR_8:$src2), imm:$lane)))))]> { let isCommutable = 0; + let NSF = NVdVnVmImmMulScalarFrm; // For disassembly. + let NSForm = NVdVnVmImmMulScalarFrm.Value; // For disassembly. } // Multiply-Add/Sub operations: single-, double- and quad-register. @@ -864,7 +988,10 @@ (Ty (ShOp (Ty DPR:$src1), (Ty (MulOp DPR:$src2, (Ty (NEONvduplane (Ty DPR_VFP2:$src3), - imm:$lane)))))))]>; + imm:$lane)))))))]> { + let NSF = NVdVnVmImmMulScalarFrm; // For disassembly. + let NSForm = NVdVnVmImmMulScalarFrm.Value; // For disassembly. +} class N3VDMulOpSL16 op21_20, bits<4> op11_8, InstrItinClass itin, string OpcodeStr, string Dt, ValueType Ty, SDNode MulOp, SDNode ShOp> @@ -876,7 +1003,10 @@ (Ty (ShOp (Ty DPR:$src1), (Ty (MulOp DPR:$src2, (Ty (NEONvduplane (Ty DPR_8:$src3), - imm:$lane)))))))]>; + imm:$lane)))))))]> { + let NSF = NVdVnVmImmMulScalarFrm; // For disassembly. + let NSForm = NVdVnVmImmMulScalarFrm.Value; // For disassembly. +} class N3VQMulOp op21_20, bits<4> op11_8, bit op4, InstrItinClass itin, string OpcodeStr, string Dt, ValueType Ty, @@ -897,7 +1027,10 @@ (ResTy (ShOp (ResTy QPR:$src1), (ResTy (MulOp QPR:$src2, (ResTy (NEONvduplane (OpTy DPR_VFP2:$src3), - imm:$lane)))))))]>; + imm:$lane)))))))]> { + let NSF = NVdVnVmImmMulScalarFrm; // For disassembly. + let NSForm = NVdVnVmImmMulScalarFrm.Value; // For disassembly. +} class N3VQMulOpSL16 op21_20, bits<4> op11_8, InstrItinClass itin, string OpcodeStr, string Dt, ValueType ResTy, ValueType OpTy, @@ -910,7 +1043,10 @@ (ResTy (ShOp (ResTy QPR:$src1), (ResTy (MulOp QPR:$src2, (ResTy (NEONvduplane (OpTy DPR_8:$src3), - imm:$lane)))))))]>; + imm:$lane)))))))]> { + let NSF = NVdVnVmImmMulScalarFrm; // For disassembly. + let NSForm = NVdVnVmImmMulScalarFrm.Value; // For disassembly. +} // Neon 3-argument intrinsics, both double- and quad-register. // The destination register is also used as the first source operand register. @@ -996,7 +1132,10 @@ [(set (ResTy QPR:$dst), (ResTy (IntOp (OpTy DPR:$src1), (OpTy (NEONvduplane (OpTy DPR_VFP2:$src2), - imm:$lane)))))]>; + imm:$lane)))))]> { + let NSF = NVdVnVmImmMulScalarFrm; // For disassembly. + let NSForm = NVdVnVmImmMulScalarFrm.Value; // For disassembly. +} class N3VLIntSL16 op21_20, bits<4> op11_8, InstrItinClass itin, string OpcodeStr, string Dt, ValueType ResTy, ValueType OpTy, Intrinsic IntOp> @@ -1006,7 +1145,10 @@ [(set (ResTy QPR:$dst), (ResTy (IntOp (OpTy DPR:$src1), (OpTy (NEONvduplane (OpTy DPR_8:$src2), - imm:$lane)))))]>; + imm:$lane)))))]> { + let NSF = NVdVnVmImmMulScalarFrm; // For disassembly. + let NSForm = NVdVnVmImmMulScalarFrm.Value; // For disassembly. +} // Wide 3-register intrinsics. class N3VWInt op21_20, bits<4> op11_8, bit op4, @@ -1055,6 +1197,10 @@ OpcodeStr, Dt, "$dst, $src2", "$src1 = $dst", [(set QPR:$dst, (ResTy (IntOp (ResTy QPR:$src1), (OpTy QPR:$src2))))]>; +// This is a big let * in block to mark these instructions NVectorShiftFrm to +// help the disassembler. +let NSF = NVectorShiftFrm, NSForm = NVectorShiftFrm.Value in { + // Shift by immediate, // both double- and quad-register. class N2VDSh op11_8, bit op7, bit op4, @@ -1072,16 +1218,6 @@ OpcodeStr, Dt, "$dst, $src, $SIMM", "", [(set QPR:$dst, (Ty (OpNode (Ty QPR:$src), (i32 imm:$SIMM))))]>; -// Long shift by immediate. -class N2VLSh op11_8, bit op7, bit op6, bit op4, - string OpcodeStr, string Dt, - ValueType ResTy, ValueType OpTy, SDNode OpNode> - : N2VImm; - // Narrow shift by immediate. class N2VNSh op11_8, bit op7, bit op6, bit op4, InstrItinClass itin, string OpcodeStr, string Dt, @@ -1124,8 +1260,26 @@ OpcodeStr, Dt, "$dst, $src2, $SIMM", "$src1 = $dst", [(set QPR:$dst, (Ty (ShOp QPR:$src1, QPR:$src2, (i32 imm:$SIMM))))]>; +} // End of "let NSF = NVectorShiftFrm, ..." + +// Long shift by immediate. +class N2VLSh op11_8, bit op7, bit op6, bit op4, + string OpcodeStr, string Dt, + ValueType ResTy, ValueType OpTy, SDNode OpNode> + : N2VImm { + // This has a different interpretation of the shift amount encoding than + // NVectorShiftFrm. + let NSF = NVectorShift2Frm; // For disassembly. + let NSForm = NVectorShift2Frm.Value; // For disassembly. +} + // Convert, with fractional bits immediate, // both double- and quad-register. +let NSF = NVdVmImmVCVTFrm, NSForm = NVdVmImmVCVTFrm.Value in { class N2VCvtD op11_8, bit op7, bit op4, string OpcodeStr, string Dt, ValueType ResTy, ValueType OpTy, Intrinsic IntOp> @@ -1140,6 +1294,7 @@ (outs QPR:$dst), (ins QPR:$src, i32imm:$SIMM), IIC_VUNAQ, OpcodeStr, Dt, "$dst, $src, $SIMM", "", [(set QPR:$dst, (ResTy (IntOp (OpTy QPR:$src), (i32 imm:$SIMM))))]>; +} //===----------------------------------------------------------------------===// // Multiclasses @@ -1350,6 +1505,60 @@ v2i64, v2i64, IntOp, Commutable>; } +// Same as N3VInt_QHSD, except they're for Vector Shift (Register) Instructions. +// D:Vd M:Vm N:Vn (notice that M:Vm is the first operand) +// This helps the disassembler. +let NSF = NVdVnVmImmVectorShiftFrm, NSForm = NVdVnVmImmVectorShiftFrm.Value in { +multiclass N3VInt_HS2 op11_8, bit op4, + InstrItinClass itinD16, InstrItinClass itinD32, + InstrItinClass itinQ16, InstrItinClass itinQ32, + string OpcodeStr, string Dt, + Intrinsic IntOp, bit Commutable = 0> { + // 64-bit vector types. + def v4i16 : N3VDInt; + def v2i32 : N3VDInt; + + // 128-bit vector types. + def v8i16 : N3VQInt; + def v4i32 : N3VQInt; +} +multiclass N3VInt_QHS2 op11_8, bit op4, + InstrItinClass itinD16, InstrItinClass itinD32, + InstrItinClass itinQ16, InstrItinClass itinQ32, + string OpcodeStr, string Dt, + Intrinsic IntOp, bit Commutable = 0> + : N3VInt_HS2 { + def v8i8 : N3VDInt; + def v16i8 : N3VQInt; +} +multiclass N3VInt_QHSD2 op11_8, bit op4, + InstrItinClass itinD16, InstrItinClass itinD32, + InstrItinClass itinQ16, InstrItinClass itinQ32, + string OpcodeStr, string Dt, + Intrinsic IntOp, bit Commutable = 0> + : N3VInt_QHS2 { + def v1i64 : N3VDInt; + def v2i64 : N3VQInt; +} +} // Neon Narrowing 3-register vector intrinsics, // source operand element sizes of 16, 32 and 64 bits: @@ -1619,6 +1828,47 @@ // imm6 = xxxxxx } +// Same as N2VSh_QHSD, except the instructions have a differnt interpretation of +// the shift amount. This helps the disassembler. +let NSF = NVectorShift2Frm, NSForm = NVectorShift2Frm.Value in { +multiclass N2VSh_QHSD2 op11_8, bit op4, + InstrItinClass itin, string OpcodeStr, string Dt, + SDNode OpNode> { + // 64-bit vector types. + def v8i8 : N2VDSh { + let Inst{21-19} = 0b001; // imm6 = 001xxx + } + def v4i16 : N2VDSh { + let Inst{21-20} = 0b01; // imm6 = 01xxxx + } + def v2i32 : N2VDSh { + let Inst{21} = 0b1; // imm6 = 1xxxxx + } + def v1i64 : N2VDSh; + // imm6 = xxxxxx + + // 128-bit vector types. + def v16i8 : N2VQSh { + let Inst{21-19} = 0b001; // imm6 = 001xxx + } + def v8i16 : N2VQSh { + let Inst{21-20} = 0b01; // imm6 = 01xxxx + } + def v4i32 : N2VQSh { + let Inst{21} = 0b1; // imm6 = 1xxxxx + } + def v2i64 : N2VQSh; + // imm6 = xxxxxx +} +} // Neon Shift-Accumulate vector operations, // element sizes of 8, 16, 32 and 64 bits: @@ -1699,6 +1949,47 @@ // imm6 = xxxxxx } +// Same as N2VShIns_QHSD, except the instructions have a differnt interpretation +// of the shift amount. This helps the disassembler. +let NSF = NVectorShift2Frm, NSForm = NVectorShift2Frm.Value in { +multiclass N2VShIns_QHSD2 op11_8, bit op4, + string OpcodeStr, SDNode ShOp> { + // 64-bit vector types. + def v8i8 : N2VDShIns { + let Inst{21-19} = 0b001; // imm6 = 001xxx + } + def v4i16 : N2VDShIns { + let Inst{21-20} = 0b01; // imm6 = 01xxxx + } + def v2i32 : N2VDShIns { + let Inst{21} = 0b1; // imm6 = 1xxxxx + } + def v1i64 : N2VDShIns; + // imm6 = xxxxxx + + // 128-bit vector types. + def v16i8 : N2VQShIns { + let Inst{21-19} = 0b001; // imm6 = 001xxx + } + def v8i16 : N2VQShIns { + let Inst{21-20} = 0b01; // imm6 = 01xxxx + } + def v4i32 : N2VQShIns { + let Inst{21} = 0b1; // imm6 = 1xxxxx + } + def v2i64 : N2VQShIns; + // imm6 = xxxxxx +} +} + // Neon Shift Long operations, // element sizes of 8, 16, 32 bits: multiclass N2VLSh_QHS op11_8, bit op7, bit op6, @@ -2329,18 +2620,21 @@ // Vector Shifts. // VSHL : Vector Shift -defm VSHLs : N3VInt_QHSD<0, 0, 0b0100, 0, IIC_VSHLiD, IIC_VSHLiD, IIC_VSHLiQ, - IIC_VSHLiQ, "vshl", "s", int_arm_neon_vshifts, 0>; -defm VSHLu : N3VInt_QHSD<1, 0, 0b0100, 0, IIC_VSHLiD, IIC_VSHLiD, IIC_VSHLiQ, - IIC_VSHLiQ, "vshl", "u", int_arm_neon_vshiftu, 0>; +defm VSHLs : N3VInt_QHSD2<0,0, 0b0100, 0, IIC_VSHLiD, IIC_VSHLiD, IIC_VSHLiQ, + IIC_VSHLiQ, "vshl", "s", int_arm_neon_vshifts, 0>; +defm VSHLu : N3VInt_QHSD2<1,0, 0b0100, 0, IIC_VSHLiD, IIC_VSHLiD, IIC_VSHLiQ, + IIC_VSHLiQ, "vshl", "u", int_arm_neon_vshiftu, 0>; // VSHL : Vector Shift Left (Immediate) -defm VSHLi : N2VSh_QHSD<0, 1, 0b0101, 1, IIC_VSHLiD, "vshl", "i", NEONvshl>; +// (disassembly note: this has a different interpretation of the shift amont) +defm VSHLi : N2VSh_QHSD2<0, 1, 0b0101, 1, IIC_VSHLiD, "vshl", "i", NEONvshl>; // VSHR : Vector Shift Right (Immediate) defm VSHRs : N2VSh_QHSD<0, 1, 0b0000, 1, IIC_VSHLiD, "vshr", "s", NEONvshrs>; defm VSHRu : N2VSh_QHSD<1, 1, 0b0000, 1, IIC_VSHLiD, "vshr", "u", NEONvshru>; // VSHLL : Vector Shift Left Long +// (disassembly note: this has a different interpretation of the shift amont) defm VSHLLs : N2VLSh_QHS<0, 1, 0b1010, 0, 0, 1, "vshll", "s", NEONvshlls>; +// (disassembly note: this has a different interpretation of the shift amont) defm VSHLLu : N2VLSh_QHS<1, 1, 0b1010, 0, 0, 1, "vshll", "u", NEONvshllu>; // VSHLL : Vector Shift Left Long (with maximum shift count) @@ -2350,6 +2644,8 @@ : N2VLSh { let Inst{21-16} = op21_16; + let NSF = NVdVmImmVSHLLFrm; // For disassembly. + let NSForm = NVdVmImmVSHLLFrm.Value; // For disassembly. } def VSHLLi8 : N2VLShMax<1, 1, 0b110010, 0b0011, 0, 0, 0, "vshll", "i8", v8i16, v8i8, NEONvshlli>; @@ -2363,10 +2659,10 @@ NEONvshrn>; // VRSHL : Vector Rounding Shift -defm VRSHLs : N3VInt_QHSD<0,0,0b0101,0, IIC_VSHLi4D, IIC_VSHLi4D, IIC_VSHLi4Q, - IIC_VSHLi4Q, "vrshl", "s", int_arm_neon_vrshifts,0>; -defm VRSHLu : N3VInt_QHSD<1,0,0b0101,0, IIC_VSHLi4D, IIC_VSHLi4D, IIC_VSHLi4Q, - IIC_VSHLi4Q, "vrshl", "u", int_arm_neon_vrshiftu,0>; +defm VRSHLs : N3VInt_QHSD2<0,0,0b0101,0,IIC_VSHLi4D, IIC_VSHLi4D, IIC_VSHLi4Q, + IIC_VSHLi4Q,"vrshl", "s", int_arm_neon_vrshifts,0>; +defm VRSHLu : N3VInt_QHSD2<1,0,0b0101,0,IIC_VSHLi4D, IIC_VSHLi4D, IIC_VSHLi4Q, + IIC_VSHLi4Q,"vrshl", "u", int_arm_neon_vrshiftu,0>; // VRSHR : Vector Rounding Shift Right defm VRSHRs : N2VSh_QHSD<0,1,0b0010,1, IIC_VSHLi4D, "vrshr", "s", NEONvrshrs>; defm VRSHRu : N2VSh_QHSD<1,1,0b0010,1, IIC_VSHLi4D, "vrshr", "u", NEONvrshru>; @@ -2376,15 +2672,18 @@ NEONvrshrn>; // VQSHL : Vector Saturating Shift -defm VQSHLs : N3VInt_QHSD<0,0,0b0100,1, IIC_VSHLi4D, IIC_VSHLi4D, IIC_VSHLi4Q, - IIC_VSHLi4Q, "vqshl", "s", int_arm_neon_vqshifts,0>; -defm VQSHLu : N3VInt_QHSD<1,0,0b0100,1, IIC_VSHLi4D, IIC_VSHLi4D, IIC_VSHLi4Q, - IIC_VSHLi4Q, "vqshl", "u", int_arm_neon_vqshiftu,0>; +defm VQSHLs : N3VInt_QHSD2<0,0,0b0100,1,IIC_VSHLi4D, IIC_VSHLi4D, IIC_VSHLi4Q, + IIC_VSHLi4Q, "vqshl", "s", int_arm_neon_vqshifts,0>; +defm VQSHLu : N3VInt_QHSD2<1,0,0b0100,1,IIC_VSHLi4D, IIC_VSHLi4D, IIC_VSHLi4Q, + IIC_VSHLi4Q, "vqshl", "u", int_arm_neon_vqshiftu,0>; // VQSHL : Vector Saturating Shift Left (Immediate) -defm VQSHLsi : N2VSh_QHSD<0,1,0b0111,1, IIC_VSHLi4D, "vqshl", "s", NEONvqshls>; -defm VQSHLui : N2VSh_QHSD<1,1,0b0111,1, IIC_VSHLi4D, "vqshl", "u", NEONvqshlu>; +// (disassembly note: this has a different interpretation of the shift amont) +defm VQSHLsi : N2VSh_QHSD2<0,1,0b0111,1, IIC_VSHLi4D, "vqshl", "s", NEONvqshls>; +// (disassembly note: this has a different interpretation of the shift amont) +defm VQSHLui : N2VSh_QHSD2<1,1,0b0111,1, IIC_VSHLi4D, "vqshl", "u", NEONvqshlu>; // VQSHLU : Vector Saturating Shift Left (Immediate, Unsigned) -defm VQSHLsu : N2VSh_QHSD<1,1,0b0110,1, IIC_VSHLi4D, "vqshlu","s",NEONvqshlsu>; +// (disassembly note: this has a different interpretation of the shift amont) +defm VQSHLsu : N2VSh_QHSD2<1,1,0b0110,1, IIC_VSHLi4D, "vqshlu","s",NEONvqshlsu>; // VQSHRN : Vector Saturating Shift Right and Narrow defm VQSHRNs : N2VNSh_HSD<0, 1, 0b1001, 0, 0, 1, IIC_VSHLi4D, "vqshrn", "s", @@ -2397,12 +2696,12 @@ NEONvqshrnsu>; // VQRSHL : Vector Saturating Rounding Shift -defm VQRSHLs : N3VInt_QHSD<0,0,0b0101,1, IIC_VSHLi4D, IIC_VSHLi4D, IIC_VSHLi4Q, - IIC_VSHLi4Q, "vqrshl", "s", - int_arm_neon_vqrshifts, 0>; -defm VQRSHLu : N3VInt_QHSD<1,0,0b0101,1, IIC_VSHLi4D, IIC_VSHLi4D, IIC_VSHLi4Q, - IIC_VSHLi4Q, "vqrshl", "u", - int_arm_neon_vqrshiftu, 0>; +defm VQRSHLs : N3VInt_QHSD2<0,0,0b0101,1, IIC_VSHLi4D, IIC_VSHLi4D, IIC_VSHLi4Q, + IIC_VSHLi4Q, "vqrshl", "s", + int_arm_neon_vqrshifts, 0>; +defm VQRSHLu : N3VInt_QHSD2<1,0,0b0101,1, IIC_VSHLi4D, IIC_VSHLi4D, IIC_VSHLi4Q, + IIC_VSHLi4Q, "vqrshl", "u", + int_arm_neon_vqrshiftu, 0>; // VQRSHRN : Vector Saturating Rounding Shift Right and Narrow defm VQRSHRNs : N2VNSh_HSD<0, 1, 0b1001, 0, 1, 1, IIC_VSHLi4D, "vqrshrn", "s", @@ -2422,7 +2721,8 @@ defm VRSRAu : N2VShAdd_QHSD<1, 1, 0b0011, 1, "vrsra", "u", NEONvrshru>; // VSLI : Vector Shift Left and Insert -defm VSLI : N2VShIns_QHSD<1, 1, 0b0101, 1, "vsli", NEONvsli>; +// (disassembly note: this has a different interpretation of the shift amont) +defm VSLI : N2VShIns_QHSD2<1, 1, 0b0101, 1, "vsli", NEONvsli>; // VSRI : Vector Shift Right and Insert defm VSRI : N2VShIns_QHSD<1, 1, 0b0100, 1, "vsri", NEONvsri>; @@ -2518,10 +2818,13 @@ // VMOV : Vector Move (Register) +// Mark these instructions as 2-register instructions to help the disassembler. +let NSF = NVdVmImmFrm, NSForm = NVdVmImmFrm.Value in { def VMOVDneon: N3VX<0, 0, 0b10, 0b0001, 0, 1, (outs DPR:$dst), (ins DPR:$src), IIC_VMOVD, "vmov", "$dst, $src", "", []>; def VMOVQ : N3VX<0, 0, 0b10, 0b0001, 1, 1, (outs QPR:$dst), (ins QPR:$src), IIC_VMOVD, "vmov", "$dst, $src", "", []>; +} // VMOV : Vector Move (Immediate) @@ -2762,6 +3065,7 @@ // VDUP : Vector Duplicate Lane (from scalar to all elements) +let NSF = NVdVmImmVDupLaneFrm, NSForm = NVdVmImmVDupLaneFrm.Value in { class VDUPLND op19_18, bits<2> op17_16, string OpcodeStr, string Dt, ValueType Ty> : N2V<0b11, 0b11, op19_18, op17_16, 0b11000, 0, 0, @@ -2775,6 +3079,7 @@ (outs QPR:$dst), (ins DPR:$src, nohash_imm:$lane), IIC_VMOVD, OpcodeStr, Dt, "$dst, $src[$lane]", "", [(set QPR:$dst, (ResTy (NEONvduplane (OpTy DPR:$src), imm:$lane)))]>; +} // Inst{19-16} is partially specified depending on the element size. @@ -2843,24 +3148,37 @@ // Vector Conversions. +let NSF = NVdVmImmVCVTFrm, NSForm = NVdVmImmVCVTFrm.Value in { +class N2VDX op24_23, bits<2> op21_20, bits<2> op19_18, + bits<2> op17_16, bits<5> op11_7, bit op4, string OpcodeStr, + string Dt, ValueType ResTy, ValueType OpTy, SDNode OpNode> + : N2VD; +class N2VQX op24_23, bits<2> op21_20, bits<2> op19_18, + bits<2> op17_16, bits<5> op11_7, bit op4, string OpcodeStr, + string Dt, ValueType ResTy, ValueType OpTy, SDNode OpNode> + : N2VQ; +} + // VCVT : Vector Convert Between Floating-Point and Integers -def VCVTf2sd : N2VD<0b11, 0b11, 0b10, 0b11, 0b01110, 0, "vcvt", "s32.f32", - v2i32, v2f32, fp_to_sint>; -def VCVTf2ud : N2VD<0b11, 0b11, 0b10, 0b11, 0b01111, 0, "vcvt", "u32.f32", - v2i32, v2f32, fp_to_uint>; -def VCVTs2fd : N2VD<0b11, 0b11, 0b10, 0b11, 0b01100, 0, "vcvt", "f32.s32", - v2f32, v2i32, sint_to_fp>; -def VCVTu2fd : N2VD<0b11, 0b11, 0b10, 0b11, 0b01101, 0, "vcvt", "f32.u32", - v2f32, v2i32, uint_to_fp>; - -def VCVTf2sq : N2VQ<0b11, 0b11, 0b10, 0b11, 0b01110, 0, "vcvt", "s32.f32", - v4i32, v4f32, fp_to_sint>; -def VCVTf2uq : N2VQ<0b11, 0b11, 0b10, 0b11, 0b01111, 0, "vcvt", "u32.f32", - v4i32, v4f32, fp_to_uint>; -def VCVTs2fq : N2VQ<0b11, 0b11, 0b10, 0b11, 0b01100, 0, "vcvt", "f32.s32", - v4f32, v4i32, sint_to_fp>; -def VCVTu2fq : N2VQ<0b11, 0b11, 0b10, 0b11, 0b01101, 0, "vcvt", "f32.u32", - v4f32, v4i32, uint_to_fp>; +def VCVTf2sd : N2VDX<0b11, 0b11, 0b10, 0b11, 0b01110, 0, "vcvt", "s32.f32", + v2i32, v2f32, fp_to_sint>; +def VCVTf2ud : N2VDX<0b11, 0b11, 0b10, 0b11, 0b01111, 0, "vcvt", "u32.f32", + v2i32, v2f32, fp_to_uint>; +def VCVTs2fd : N2VDX<0b11, 0b11, 0b10, 0b11, 0b01100, 0, "vcvt", "f32.s32", + v2f32, v2i32, sint_to_fp>; +def VCVTu2fd : N2VDX<0b11, 0b11, 0b10, 0b11, 0b01101, 0, "vcvt", "f32.u32", + v2f32, v2i32, uint_to_fp>; + +def VCVTf2sq : N2VQX<0b11, 0b11, 0b10, 0b11, 0b01110, 0, "vcvt", "s32.f32", + v4i32, v4f32, fp_to_sint>; +def VCVTf2uq : N2VQX<0b11, 0b11, 0b10, 0b11, 0b01111, 0, "vcvt", "u32.f32", + v4i32, v4f32, fp_to_uint>; +def VCVTs2fq : N2VQX<0b11, 0b11, 0b10, 0b11, 0b01100, 0, "vcvt", "f32.s32", + v4f32, v4i32, sint_to_fp>; +def VCVTu2fq : N2VQX<0b11, 0b11, 0b10, 0b11, 0b01101, 0, "vcvt", "f32.u32", + v4f32, v4i32, uint_to_fp>; // VCVT : Vector Convert Between Floating-Point and Fixed-Point. def VCVTf2xsd : N2VCvtD<0, 1, 0b1111, 0, 1, "vcvt", "s32.f32", @@ -2945,6 +3263,8 @@ // VEXT : Vector Extract +let NSF = NVdVnVmImmVectorExtractFrm, + NSForm = NVdVnVmImmVectorExtractFrm.Value in { class VEXTd : N3V<0,1,0b11,{?,?,?,?},0,0, (outs DPR:$dst), (ins DPR:$lhs, DPR:$rhs, i32imm:$index), IIC_VEXTD, @@ -2958,6 +3278,7 @@ OpcodeStr, Dt, "$dst, $lhs, $rhs, $index", "", [(set QPR:$dst, (Ty (NEONvext (Ty QPR:$lhs), (Ty QPR:$rhs), imm:$index)))]>; +} def VEXTd8 : VEXTd<"vext", "8", v8i8>; def VEXTd16 : VEXTd<"vext", "16", v4i16>; @@ -3001,6 +3322,8 @@ // Vector Table Lookup and Table Extension. +let NSF = VTBLFrm, NSForm = VTBLFrm.Value in { + // VTBL : Vector Table Lookup def VTBL1 : N3V<1,1,0b11,0b1000,0,0, (outs DPR:$dst), @@ -3057,6 +3380,8 @@ DPR:$tbl2, DPR:$tbl3, DPR:$tbl4, DPR:$src)))]>; } // hasExtraSrcRegAllocReq = 1 +} // End of "let NSF = VTBLFrm, ..." + //===----------------------------------------------------------------------===// // NEON instructions for single-precision FP math //===----------------------------------------------------------------------===// Modified: llvm/trunk/lib/Target/ARM/AsmPrinter/ARMAsmPrinter.cpp URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Target/ARM/AsmPrinter/ARMAsmPrinter.cpp?rev=98637&r1=98636&r2=98637&view=diff ============================================================================== --- llvm/trunk/lib/Target/ARM/AsmPrinter/ARMAsmPrinter.cpp (original) +++ llvm/trunk/lib/Target/ARM/AsmPrinter/ARMAsmPrinter.cpp Tue Mar 16 11:36:54 2010 @@ -120,7 +120,7 @@ void printT2AddrModeImm8Operand(const MachineInstr *MI, int OpNum); void printT2AddrModeImm8s4Operand(const MachineInstr *MI, int OpNum); void printT2AddrModeImm8OffsetOperand(const MachineInstr *MI, int OpNum); - void printT2AddrModeImm8s4OffsetOperand(const MachineInstr *MI, int OpNum) {} + void printT2AddrModeImm8s4OffsetOperand(const MachineInstr *MI, int OpNum); void printT2AddrModeSoRegOperand(const MachineInstr *MI, int OpNum); void printCPSOptionOperand(const MachineInstr *MI, int OpNum) {} @@ -431,16 +431,16 @@ O << "[" << getRegisterName(MO1.getReg()); if (!MO2.getReg()) { - if (ARM_AM::getAM2Offset(MO3.getImm())) // Don't print +0. + if (ARM_AM::getAM2Offset(MO3.getImm())) // Don't print +0. O << ", #" - << (char)ARM_AM::getAM2Op(MO3.getImm()) + << ARM_AM::getAddrOpcStr(ARM_AM::getAM2Op(MO3.getImm())) << ARM_AM::getAM2Offset(MO3.getImm()); O << "]"; return; } O << ", " - << (char)ARM_AM::getAM2Op(MO3.getImm()) + << ARM_AM::getAddrOpcStr(ARM_AM::getAM2Op(MO3.getImm())) << getRegisterName(MO2.getReg()); if (unsigned ShImm = ARM_AM::getAM2Offset(MO3.getImm())) @@ -458,12 +458,12 @@ unsigned ImmOffs = ARM_AM::getAM2Offset(MO2.getImm()); assert(ImmOffs && "Malformed indexed load / store!"); O << "#" - << (char)ARM_AM::getAM2Op(MO2.getImm()) + << ARM_AM::getAddrOpcStr(ARM_AM::getAM2Op(MO2.getImm())) << ImmOffs; return; } - O << (char)ARM_AM::getAM2Op(MO2.getImm()) + O << ARM_AM::getAddrOpcStr(ARM_AM::getAM2Op(MO2.getImm())) << getRegisterName(MO1.getReg()); if (unsigned ShImm = ARM_AM::getAM2Offset(MO2.getImm())) @@ -490,7 +490,7 @@ if (unsigned ImmOffs = ARM_AM::getAM3Offset(MO3.getImm())) O << ", #" - << (char)ARM_AM::getAM3Op(MO3.getImm()) + << ARM_AM::getAddrOpcStr(ARM_AM::getAM3Op(MO3.getImm())) << ImmOffs; O << "]"; } @@ -508,7 +508,7 @@ unsigned ImmOffs = ARM_AM::getAM3Offset(MO2.getImm()); assert(ImmOffs && "Malformed indexed load / store!"); O << "#" - << (char)ARM_AM::getAM3Op(MO2.getImm()) + << ARM_AM::getAddrOpcStr(ARM_AM::getAM3Op(MO2.getImm())) << ImmOffs; } @@ -558,7 +558,7 @@ if (unsigned ImmOffs = ARM_AM::getAM5Offset(MO2.getImm())) { O << ", #" - << (char)ARM_AM::getAM5Op(MO2.getImm()) + << ARM_AM::getAddrOpcStr(ARM_AM::getAM5Op(MO2.getImm())) << ImmOffs*4; } O << "]"; @@ -594,7 +594,7 @@ const MachineOperand &MO1 = MI->getOperand(Op); assert(TargetRegisterInfo::isPhysicalRegister(MO1.getReg())); - O << "[pc, +" << getRegisterName(MO1.getReg()) << "]"; + O << "[pc, " << getRegisterName(MO1.getReg()) << "]"; } void @@ -617,10 +617,11 @@ ARMAsmPrinter::printThumbITMask(const MachineInstr *MI, int Op) { // (3 - the number of trailing zeros) is the number of then / else. unsigned Mask = MI->getOperand(Op).getImm(); + unsigned CondBit0 = Mask >> 4 & 1; unsigned NumTZ = CountTrailingZeros_32(Mask); assert(NumTZ <= 3 && "Invalid IT mask!"); for (unsigned Pos = 3, e = NumTZ; Pos > e; --Pos) { - bool T = (Mask & (1 << Pos)) == 0; + bool T = ((Mask >> Pos) & 1) == CondBit0; if (T) O << 't'; else @@ -652,7 +653,7 @@ if (MO3.getReg()) O << ", " << getRegisterName(MO3.getReg()); else if (unsigned ImmOffs = MO2.getImm()) - O << ", #+" << ImmOffs * Scale; + O << ", #" << ImmOffs * Scale; O << "]"; } @@ -674,7 +675,7 @@ const MachineOperand &MO2 = MI->getOperand(Op+1); O << "[" << getRegisterName(MO1.getReg()); if (unsigned ImmOffs = MO2.getImm()) - O << ", #+" << ImmOffs*4; + O << ", #" << ImmOffs*4; O << "]"; } @@ -710,7 +711,7 @@ unsigned OffImm = MO2.getImm(); if (OffImm) // Don't print +0. - O << ", #+" << OffImm; + O << ", #" << OffImm; O << "]"; } @@ -726,7 +727,7 @@ if (OffImm < 0) O << ", #-" << -OffImm; else if (OffImm > 0) - O << ", #+" << OffImm; + O << ", #" << OffImm; O << "]"; } @@ -742,7 +743,7 @@ if (OffImm < 0) O << ", #-" << -OffImm * 4; else if (OffImm > 0) - O << ", #+" << OffImm * 4; + O << ", #" << OffImm * 4; O << "]"; } @@ -754,7 +755,18 @@ if (OffImm < 0) O << "#-" << -OffImm; else if (OffImm > 0) - O << "#+" << OffImm; + O << "#" << OffImm; +} + +void ARMAsmPrinter::printT2AddrModeImm8s4OffsetOperand(const MachineInstr *MI, + int OpNum) { + const MachineOperand &MO1 = MI->getOperand(OpNum); + int32_t OffImm = (int32_t)MO1.getImm() / 4; + // Don't print +0. + if (OffImm < 0) + O << "#-" << -OffImm * 4; + else if (OffImm > 0) + O << "#" << OffImm * 4; } void ARMAsmPrinter::printT2AddrModeSoRegOperand(const MachineInstr *MI, Modified: llvm/trunk/lib/Target/ARM/AsmPrinter/ARMInstPrinter.cpp URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Target/ARM/AsmPrinter/ARMInstPrinter.cpp?rev=98637&r1=98636&r2=98637&view=diff ============================================================================== --- llvm/trunk/lib/Target/ARM/AsmPrinter/ARMInstPrinter.cpp (original) +++ llvm/trunk/lib/Target/ARM/AsmPrinter/ARMInstPrinter.cpp Tue Mar 16 11:36:54 2010 @@ -28,7 +28,165 @@ #undef MachineInstr #undef ARMAsmPrinter -void ARMInstPrinter::printInst(const MCInst *MI) { printInstruction(MI); } +static unsigned NextReg(unsigned Reg) { + switch (Reg) { + case ARM::D0: + return ARM::D1; + case ARM::D1: + return ARM::D2; + case ARM::D2: + return ARM::D3; + case ARM::D3: + return ARM::D4; + case ARM::D4: + return ARM::D5; + case ARM::D5: + return ARM::D6; + case ARM::D6: + return ARM::D7; + case ARM::D7: + return ARM::D8; + case ARM::D8: + return ARM::D9; + case ARM::D9: + return ARM::D10; + case ARM::D10: + return ARM::D11; + case ARM::D11: + return ARM::D12; + case ARM::D12: + return ARM::D13; + case ARM::D13: + return ARM::D14; + case ARM::D14: + return ARM::D15; + case ARM::D15: + return ARM::D16; + case ARM::D16: + return ARM::D17; + case ARM::D17: + return ARM::D18; + case ARM::D18: + return ARM::D19; + case ARM::D19: + return ARM::D20; + case ARM::D20: + return ARM::D21; + case ARM::D21: + return ARM::D22; + case ARM::D22: + return ARM::D23; + case ARM::D23: + return ARM::D24; + case ARM::D24: + return ARM::D25; + case ARM::D25: + return ARM::D26; + case ARM::D26: + return ARM::D27; + case ARM::D27: + return ARM::D28; + case ARM::D28: + return ARM::D29; + case ARM::D29: + return ARM::D30; + case ARM::D30: + return ARM::D31; + + default: + assert(0 && "Unexpected register enum"); + } +} + +void ARMInstPrinter::printInst(const MCInst *MI) { + // Check for MOVs and print canonical forms, instead. + if (MI->getOpcode() == ARM::MOVs) { + const MCOperand &Dst = MI->getOperand(0); + const MCOperand &MO1 = MI->getOperand(1); + const MCOperand &MO2 = MI->getOperand(2); + const MCOperand &MO3 = MI->getOperand(3); + + O << '\t' << ARM_AM::getShiftOpcStr(ARM_AM::getSORegShOp(MO3.getImm())); + printSBitModifierOperand(MI, 6); + printPredicateOperand(MI, 4); + + O << '\t' << getRegisterName(Dst.getReg()) + << ", " << getRegisterName(MO1.getReg()); + + if (ARM_AM::getSORegShOp(MO3.getImm()) == ARM_AM::rrx) + return; + + O << ", "; + + if (MO2.getReg()) { + O << getRegisterName(MO2.getReg()); + assert(ARM_AM::getSORegOffset(MO3.getImm()) == 0); + } else { + O << "#" << ARM_AM::getSORegOffset(MO3.getImm()); + } + return; + } + + // A8.6.123 PUSH + if ((MI->getOpcode() == ARM::STM || MI->getOpcode() == ARM::t2STM_UPD) && + MI->getOperand(0).getReg() == ARM::SP) { + const unsigned IdxOffset = MI->getOpcode() == ARM::STM ? 0 : 1; + const MCOperand &MO1 = MI->getOperand(IdxOffset + 1); + if (ARM_AM::getAM4WBFlag(MO1.getImm()) && + ARM_AM::getAM4SubMode(MO1.getImm()) == ARM_AM::db) { + O << '\t' << "push"; + printPredicateOperand(MI, IdxOffset + 2); + O << '\t'; + printRegisterList(MI, IdxOffset + 4); + return; + } + } + + // A8.6.122 POP + if ((MI->getOpcode() == ARM::LDM || MI->getOpcode() == ARM::t2LDM_UPD) && + MI->getOperand(0).getReg() == ARM::SP) { + const unsigned IdxOffset = MI->getOpcode() == ARM::LDM ? 0 : 1; + const MCOperand &MO1 = MI->getOperand(IdxOffset + 1); + if (ARM_AM::getAM4WBFlag(MO1.getImm()) && + ARM_AM::getAM4SubMode(MO1.getImm()) == ARM_AM::ia) { + O << '\t' << "pop"; + printPredicateOperand(MI, IdxOffset + 2); + O << '\t'; + printRegisterList(MI, IdxOffset + 4); + return; + } + } + + // A8.6.355 VPUSH + if ((MI->getOpcode() == ARM::VSTMS || MI->getOpcode() == ARM::VSTMD) && + MI->getOperand(0).getReg() == ARM::SP) { + const MCOperand &MO1 = MI->getOperand(1); + if (ARM_AM::getAM5WBFlag(MO1.getImm()) && + ARM_AM::getAM5SubMode(MO1.getImm()) == ARM_AM::db) { + O << '\t' << "vpush"; + printPredicateOperand(MI, 2); + O << '\t'; + printRegisterList(MI, 4); + return; + } + } + + // A8.6.354 VPOP + if ((MI->getOpcode() == ARM::VLDMS || MI->getOpcode() == ARM::VLDMD) && + MI->getOperand(0).getReg() == ARM::SP) { + const MCOperand &MO1 = MI->getOperand(1); + if (ARM_AM::getAM5WBFlag(MO1.getImm()) && + ARM_AM::getAM5SubMode(MO1.getImm()) == ARM_AM::ia) { + O << '\t' << "vpop"; + printPredicateOperand(MI, 2); + O << '\t'; + printRegisterList(MI, 4); + return; + } + } + + printInstruction(MI); + } void ARMInstPrinter::printOperand(const MCInst *MI, unsigned OpNo, const char *Modifier) { @@ -36,6 +194,9 @@ if (Op.isReg()) { unsigned Reg = Op.getReg(); if (Modifier && strcmp(Modifier, "dregpair") == 0) { + O << '{' << getRegisterName(Reg) << ", " + << getRegisterName(NextReg(Reg)) << '}'; +#if 0 // FIXME: Breaks e.g. ARM/vmul.ll. assert(0); /* @@ -44,6 +205,7 @@ O << '{' << getRegisterName(DRegLo) << ',' << getRegisterName(DRegHi) << '}';*/ +#endif } else if (Modifier && strcmp(Modifier, "lane") == 0) { assert(0); /* @@ -56,7 +218,9 @@ O << getRegisterName(Reg); } } else if (Op.isImm()) { - assert((Modifier == 0 || Modifier[0] == 0) && "No modifiers supported"); + bool isCallOp = Modifier && !strcmp(Modifier, "call"); + assert(isCallOp || + ((Modifier == 0 || Modifier[0] == 0) && "No modifiers supported")); O << '#' << Op.getImm(); } else { assert((Modifier == 0 || Modifier[0] == 0) && "No modifiers supported"); @@ -142,17 +306,17 @@ O << "[" << getRegisterName(MO1.getReg()); if (!MO2.getReg()) { - if (ARM_AM::getAM2Offset(MO3.getImm())) // Don't print +0. + if (ARM_AM::getAM2Offset(MO3.getImm())) // Don't print +0. O << ", #" - << (char)ARM_AM::getAM2Op(MO3.getImm()) - << ARM_AM::getAM2Offset(MO3.getImm()); + << ARM_AM::getAddrOpcStr(ARM_AM::getAM2Op(MO3.getImm())) + << ARM_AM::getAM2Offset(MO3.getImm()); O << "]"; return; } O << ", " - << (char)ARM_AM::getAM2Op(MO3.getImm()) - << getRegisterName(MO2.getReg()); + << ARM_AM::getAddrOpcStr(ARM_AM::getAM2Op(MO3.getImm())) + << getRegisterName(MO2.getReg()); if (unsigned ShImm = ARM_AM::getAM2Offset(MO3.getImm())) O << ", " @@ -169,11 +333,14 @@ if (!MO1.getReg()) { unsigned ImmOffs = ARM_AM::getAM2Offset(MO2.getImm()); assert(ImmOffs && "Malformed indexed load / store!"); - O << '#' << (char)ARM_AM::getAM2Op(MO2.getImm()) << ImmOffs; + O << '#' + << ARM_AM::getAddrOpcStr(ARM_AM::getAM2Op(MO2.getImm())) + << ImmOffs; return; } - O << (char)ARM_AM::getAM2Op(MO2.getImm()) << getRegisterName(MO1.getReg()); + O << ARM_AM::getAddrOpcStr(ARM_AM::getAM2Op(MO2.getImm())) + << getRegisterName(MO1.getReg()); if (unsigned ShImm = ARM_AM::getAM2Offset(MO2.getImm())) O << ", " @@ -196,8 +363,8 @@ if (unsigned ImmOffs = ARM_AM::getAM3Offset(MO3.getImm())) O << ", #" - << (char)ARM_AM::getAM3Op(MO3.getImm()) - << ImmOffs; + << ARM_AM::getAddrOpcStr(ARM_AM::getAM3Op(MO3.getImm())) + << ImmOffs; O << ']'; } @@ -214,9 +381,9 @@ unsigned ImmOffs = ARM_AM::getAM3Offset(MO2.getImm()); assert(ImmOffs && "Malformed indexed load / store!"); - O << "#" - << (char)ARM_AM::getAM3Op(MO2.getImm()) - << ImmOffs; + O << '#' + << ARM_AM::getAddrOpcStr(ARM_AM::getAM3Op(MO2.getImm())) + << ImmOffs; } @@ -264,7 +431,7 @@ if (unsigned ImmOffs = ARM_AM::getAM5Offset(MO2.getImm())) { O << ", #" - << (char)ARM_AM::getAM5Op(MO2.getImm()) + << ARM_AM::getAddrOpcStr(ARM_AM::getAM5Op(MO2.getImm())) << ImmOffs*4; } O << "]"; @@ -303,14 +470,56 @@ void ARMInstPrinter::printRegisterList(const MCInst *MI, unsigned OpNum) { O << "{"; - // Always skip the first operand, it's the optional (and implicit writeback). - for (unsigned i = OpNum+1, e = MI->getNumOperands(); i != e; ++i) { - if (i != OpNum+1) O << ", "; + for (unsigned i = OpNum, e = MI->getNumOperands(); i != e; ++i) { + if (i != OpNum) O << ", "; O << getRegisterName(MI->getOperand(i).getReg()); } O << "}"; } +void ARMInstPrinter::printCPSOptionOperand(const MCInst *MI, unsigned OpNum) { + const MCOperand &Op = MI->getOperand(OpNum); + unsigned option = Op.getImm(); + unsigned mode = option & 31; + bool changemode = option >> 5 & 1; + unsigned AIF = option >> 6 & 7; + unsigned imod = option >> 9 & 3; + if (imod == 2) + O << "ie"; + else if (imod == 3) + O << "id"; + O << '\t'; + if (imod > 1) { + if (AIF & 4) O << 'a'; + if (AIF & 2) O << 'i'; + if (AIF & 1) O << 'f'; + if (AIF > 0 && changemode) O << ", "; + } + if (changemode) + O << '#' << mode; +} + +void ARMInstPrinter::printMSRMaskOperand(const MCInst *MI, unsigned OpNum) { + const MCOperand &Op = MI->getOperand(OpNum); + unsigned Mask = Op.getImm(); + if (Mask) { + O << '_'; + if (Mask & 8) O << 'f'; + if (Mask & 4) O << 's'; + if (Mask & 2) O << 'x'; + if (Mask & 1) O << 'c'; + } +} + +void ARMInstPrinter::printNegZeroOperand(const MCInst *MI, unsigned OpNum){ + const MCOperand &Op = MI->getOperand(OpNum); + O << '#'; + if (Op.getImm() < 0) + O << '-' << (-Op.getImm() - 1); + else + O << Op.getImm(); +} + void ARMInstPrinter::printPredicateOperand(const MCInst *MI, unsigned OpNum) { ARMCC::CondCodes CC = (ARMCC::CondCodes)MI->getOperand(OpNum).getImm(); if (CC != ARMCC::AL) @@ -352,3 +561,191 @@ void ARMInstPrinter::printThumbS4ImmOperand(const MCInst *MI, unsigned OpNum) { O << "#" << MI->getOperand(OpNum).getImm() * 4; } + +void ARMInstPrinter::printThumbITMask(const MCInst *MI, unsigned OpNum) { + // (3 - the number of trailing zeros) is the number of then / else. + unsigned Mask = MI->getOperand(OpNum).getImm(); + unsigned CondBit0 = Mask >> 4 & 1; + unsigned NumTZ = CountTrailingZeros_32(Mask); + assert(NumTZ <= 3 && "Invalid IT mask!"); + for (unsigned Pos = 3, e = NumTZ; Pos > e; --Pos) { + bool T = ((Mask >> Pos) & 1) == CondBit0; + if (T) + O << 't'; + else + O << 'e'; + } +} + +void ARMInstPrinter::printThumbAddrModeRROperand(const MCInst *MI, unsigned Op) +{ + const MCOperand &MO1 = MI->getOperand(Op); + const MCOperand &MO2 = MI->getOperand(Op+1); + O << "[" << getRegisterName(MO1.getReg()); + O << ", " << getRegisterName(MO2.getReg()) << "]"; +} + +void ARMInstPrinter::printThumbAddrModeRI5Operand(const MCInst *MI, unsigned Op, + unsigned Scale) { + const MCOperand &MO1 = MI->getOperand(Op); + const MCOperand &MO2 = MI->getOperand(Op+1); + const MCOperand &MO3 = MI->getOperand(Op+2); + + if (!MO1.isReg()) { // FIXME: This is for CP entries, but isn't right. + printOperand(MI, Op); + return; + } + + O << "[" << getRegisterName(MO1.getReg()); + if (MO3.getReg()) + O << ", " << getRegisterName(MO3.getReg()); + else if (unsigned ImmOffs = MO2.getImm()) + O << ", #" << ImmOffs * Scale; + O << "]"; +} + +void ARMInstPrinter::printThumbAddrModeS1Operand(const MCInst *MI, unsigned Op) +{ + printThumbAddrModeRI5Operand(MI, Op, 1); +} + +void ARMInstPrinter::printThumbAddrModeS2Operand(const MCInst *MI, unsigned Op) +{ + printThumbAddrModeRI5Operand(MI, Op, 2); +} + +void ARMInstPrinter::printThumbAddrModeS4Operand(const MCInst *MI, unsigned Op) +{ + printThumbAddrModeRI5Operand(MI, Op, 4); +} + +void ARMInstPrinter::printThumbAddrModeSPOperand(const MCInst *MI,unsigned Op) { + const MCOperand &MO1 = MI->getOperand(Op); + const MCOperand &MO2 = MI->getOperand(Op+1); + O << "[" << getRegisterName(MO1.getReg()); + if (unsigned ImmOffs = MO2.getImm()) + O << ", #" << ImmOffs*4; + O << "]"; +} + +void ARMInstPrinter::printTBAddrMode(const MCInst *MI, unsigned OpNum) { + O << "[pc, " << getRegisterName(MI->getOperand(OpNum).getReg()); + if (MI->getOpcode() == ARM::t2TBH) + O << ", lsl #1"; + O << ']'; +} + +// Constant shifts t2_so_reg is a 2-operand unit corresponding to the Thumb2 +// register with shift forms. +// REG 0 0 - e.g. R5 +// REG IMM, SH_OPC - e.g. R5, LSL #3 +void ARMInstPrinter::printT2SOOperand(const MCInst *MI, unsigned OpNum) { + const MCOperand &MO1 = MI->getOperand(OpNum); + const MCOperand &MO2 = MI->getOperand(OpNum+1); + + unsigned Reg = MO1.getReg(); + O << getRegisterName(Reg); + + // Print the shift opc. + O << ", " + << ARM_AM::getShiftOpcStr(ARM_AM::getSORegShOp(MO2.getImm())) + << " "; + + assert(MO2.isImm() && "Not a valid t2_so_reg value!"); + O << "#" << ARM_AM::getSORegOffset(MO2.getImm()); +} + +void ARMInstPrinter::printT2AddrModeImm12Operand(const MCInst *MI, + unsigned OpNum) { + const MCOperand &MO1 = MI->getOperand(OpNum); + const MCOperand &MO2 = MI->getOperand(OpNum+1); + + O << "[" << getRegisterName(MO1.getReg()); + + unsigned OffImm = MO2.getImm(); + if (OffImm) // Don't print +0. + O << ", #" << OffImm; + O << "]"; +} + +void ARMInstPrinter::printT2AddrModeImm8Operand(const MCInst *MI, + unsigned OpNum) { + const MCOperand &MO1 = MI->getOperand(OpNum); + const MCOperand &MO2 = MI->getOperand(OpNum+1); + + O << "[" << getRegisterName(MO1.getReg()); + + int32_t OffImm = (int32_t)MO2.getImm(); + // Don't print +0. + if (OffImm < 0) + O << ", #-" << -OffImm; + else if (OffImm > 0) + O << ", #" << OffImm; + O << "]"; +} + +void ARMInstPrinter::printT2AddrModeImm8s4Operand(const MCInst *MI, + unsigned OpNum) { + const MCOperand &MO1 = MI->getOperand(OpNum); + const MCOperand &MO2 = MI->getOperand(OpNum+1); + + O << "[" << getRegisterName(MO1.getReg()); + + int32_t OffImm = (int32_t)MO2.getImm() / 4; + // Don't print +0. + if (OffImm < 0) + O << ", #-" << -OffImm * 4; + else if (OffImm > 0) + O << ", #" << OffImm * 4; + O << "]"; +} + +void ARMInstPrinter::printT2AddrModeImm8OffsetOperand(const MCInst *MI, + unsigned OpNum) { + const MCOperand &MO1 = MI->getOperand(OpNum); + int32_t OffImm = (int32_t)MO1.getImm(); + // Don't print +0. + if (OffImm < 0) + O << "#-" << -OffImm; + else if (OffImm > 0) + O << "#" << OffImm; +} + +void ARMInstPrinter::printT2AddrModeImm8s4OffsetOperand(const MCInst *MI, + unsigned OpNum) { + const MCOperand &MO1 = MI->getOperand(OpNum); + int32_t OffImm = (int32_t)MO1.getImm() / 4; + // Don't print +0. + if (OffImm < 0) + O << "#-" << -OffImm * 4; + else if (OffImm > 0) + O << "#" << OffImm * 4; +} + +void ARMInstPrinter::printT2AddrModeSoRegOperand(const MCInst *MI, + unsigned OpNum) { + const MCOperand &MO1 = MI->getOperand(OpNum); + const MCOperand &MO2 = MI->getOperand(OpNum+1); + const MCOperand &MO3 = MI->getOperand(OpNum+2); + + O << "[" << getRegisterName(MO1.getReg()); + + assert(MO2.getReg() && "Invalid so_reg load / store address!"); + O << ", " << getRegisterName(MO2.getReg()); + + unsigned ShAmt = MO3.getImm(); + if (ShAmt) { + assert(ShAmt <= 3 && "Not a valid Thumb2 addressing mode!"); + O << ", lsl #" << ShAmt; + } + O << "]"; +} + +void ARMInstPrinter::printVFPf32ImmOperand(const MCInst *MI, unsigned OpNum) { + O << '#' << MI->getOperand(OpNum).getImm(); +} + +void ARMInstPrinter::printVFPf64ImmOperand(const MCInst *MI, unsigned OpNum) { + O << '#' << MI->getOperand(OpNum).getImm(); +} + Modified: llvm/trunk/lib/Target/ARM/AsmPrinter/ARMInstPrinter.h URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Target/ARM/AsmPrinter/ARMInstPrinter.h?rev=98637&r1=98636&r2=98637&view=diff ============================================================================== --- llvm/trunk/lib/Target/ARM/AsmPrinter/ARMInstPrinter.h (original) +++ llvm/trunk/lib/Target/ARM/AsmPrinter/ARMInstPrinter.h Tue Mar 16 11:36:54 2010 @@ -54,26 +54,26 @@ void printBitfieldInvMaskImmOperand(const MCInst *MI, unsigned OpNum); void printThumbS4ImmOperand(const MCInst *MI, unsigned OpNum); - void printThumbITMask(const MCInst *MI, unsigned OpNum) {} - void printThumbAddrModeRROperand(const MCInst *MI, unsigned OpNum) {} + void printThumbITMask(const MCInst *MI, unsigned OpNum); + void printThumbAddrModeRROperand(const MCInst *MI, unsigned OpNum); void printThumbAddrModeRI5Operand(const MCInst *MI, unsigned OpNum, - unsigned Scale) {} - void printThumbAddrModeS1Operand(const MCInst *MI, unsigned OpNum) {} - void printThumbAddrModeS2Operand(const MCInst *MI, unsigned OpNum) {} - void printThumbAddrModeS4Operand(const MCInst *MI, unsigned OpNum) {} - void printThumbAddrModeSPOperand(const MCInst *MI, unsigned OpNum) {} + unsigned Scale); + void printThumbAddrModeS1Operand(const MCInst *MI, unsigned OpNum); + void printThumbAddrModeS2Operand(const MCInst *MI, unsigned OpNum); + void printThumbAddrModeS4Operand(const MCInst *MI, unsigned OpNum); + void printThumbAddrModeSPOperand(const MCInst *MI, unsigned OpNum); - void printT2SOOperand(const MCInst *MI, unsigned OpNum) {} - void printT2AddrModeImm12Operand(const MCInst *MI, unsigned OpNum) {} - void printT2AddrModeImm8Operand(const MCInst *MI, unsigned OpNum) {} - void printT2AddrModeImm8s4Operand(const MCInst *MI, unsigned OpNum) {} - void printT2AddrModeImm8OffsetOperand(const MCInst *MI, unsigned OpNum) {} - void printT2AddrModeImm8s4OffsetOperand(const MCInst *MI, unsigned OpNum) {} - void printT2AddrModeSoRegOperand(const MCInst *MI, unsigned OpNum) {} + void printT2SOOperand(const MCInst *MI, unsigned OpNum); + void printT2AddrModeImm12Operand(const MCInst *MI, unsigned OpNum); + void printT2AddrModeImm8Operand(const MCInst *MI, unsigned OpNum); + void printT2AddrModeImm8s4Operand(const MCInst *MI, unsigned OpNum); + void printT2AddrModeImm8OffsetOperand(const MCInst *MI, unsigned OpNum); + void printT2AddrModeImm8s4OffsetOperand(const MCInst *MI, unsigned OpNum); + void printT2AddrModeSoRegOperand(const MCInst *MI, unsigned OpNum); - void printCPSOptionOperand(const MCInst *MI, unsigned OpNum) {} - void printMSRMaskOperand(const MCInst *MI, unsigned OpNum) {} - void printNegZeroOperand(const MCInst *MI, unsigned OpNum) {} + void printCPSOptionOperand(const MCInst *MI, unsigned OpNum); + void printMSRMaskOperand(const MCInst *MI, unsigned OpNum); + void printNegZeroOperand(const MCInst *MI, unsigned OpNum); void printPredicateOperand(const MCInst *MI, unsigned OpNum); void printMandatoryPredicateOperand(const MCInst *MI, unsigned OpNum); void printSBitModifierOperand(const MCInst *MI, unsigned OpNum); @@ -82,10 +82,10 @@ const char *Modifier); void printJTBlockOperand(const MCInst *MI, unsigned OpNum) {} void printJT2BlockOperand(const MCInst *MI, unsigned OpNum) {} - void printTBAddrMode(const MCInst *MI, unsigned OpNum) {} + void printTBAddrMode(const MCInst *MI, unsigned OpNum); void printNoHashImmediate(const MCInst *MI, unsigned OpNum); - void printVFPf32ImmOperand(const MCInst *MI, int OpNum) {} - void printVFPf64ImmOperand(const MCInst *MI, int OpNum) {} + void printVFPf32ImmOperand(const MCInst *MI, unsigned OpNum); + void printVFPf64ImmOperand(const MCInst *MI, unsigned OpNum); void printHex8ImmOperand(const MCInst *MI, int OpNum) {} void printHex16ImmOperand(const MCInst *MI, int OpNum) {} void printHex32ImmOperand(const MCInst *MI, int OpNum) {} Added: llvm/trunk/lib/Target/ARM/Disassembler/ARMDisassembler.cpp URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Target/ARM/Disassembler/ARMDisassembler.cpp?rev=98637&view=auto ============================================================================== --- llvm/trunk/lib/Target/ARM/Disassembler/ARMDisassembler.cpp (added) +++ llvm/trunk/lib/Target/ARM/Disassembler/ARMDisassembler.cpp Tue Mar 16 11:36:54 2010 @@ -0,0 +1,513 @@ +//===- ARMDisassembler.cpp - Disassembler for ARM/Thumb ISA ----*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file is part of the ARM Disassembler. +// It contains code to translate the data produced by the decoder into MCInsts. +// Documentation for the disassembler can be found in ARMDisassembler.h. +// +//===----------------------------------------------------------------------===// + +#define DEBUG_TYPE "arm-disassembler" + +#include "ARMDisassembler.h" +#include "ARMDisassemblerCore.h" + +#include "llvm/MC/MCInst.h" +#include "llvm/Target/TargetRegistry.h" +#include "llvm/Support/Debug.h" +#include "llvm/Support/MemoryObject.h" +#include "llvm/Support/ErrorHandling.h" +#include "llvm/Support/raw_ostream.h" + +/// ARMDisassemblerTables.inc - ARMDisassemblerTables.inc is tblgen'ed from +/// RISCDisassemblerEmitter.cpp TableGen backend. It contains: +/// +/// o Mappings from opcode to ARM/Thumb instruction format +/// +/// o static uint16_t decodeInstruction(uint32_t insn) - the decoding function +/// for an ARM instruction. +/// +/// o static uint16_t decodeThumbInstruction(field_t insn) - the decoding +/// function for a Thumb instruction. +/// +#include "../ARMGenDisassemblerTables.inc" + +namespace llvm { + +namespace ARMDisassembler { + +/// showBitVector - Use the raw_ostream to log a diagnostic message describing +/// the inidividual bits of the instruction. This is a sample output: +/// +/// 31 30 29 28 27 26 25 24 23 22 21 20 19 18 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0 +/// ------------------------------------------------------------------------------------------------- +/// | 1: 0: 1: 0| 1: 0: 1: 0| 1: 0: 1: 0| 1: 0: 1: 0| 1: 0: 1: 0| 1: 0: 1: 0| 1: 0: 1: 0| 1: 0: 1: 0| +/// ------------------------------------------------------------------------------------------------- +/// +static inline void showBitVector(raw_ostream &os, const uint32_t &insn) { + os << " 31 30 29 28 27 26 25 24 23 22 21 20 19 18 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0 \n"; + os << "-------------------------------------------------------------------------------------------------\n"; + os << '|'; + for (unsigned i = 32; i != 0; --i) { + if (insn >> (i - 1) & 0x01) + os << " 1"; + else + os << " 0"; + os << (i%4 == 1 ? '|' : ':'); + } + os << '\n'; + os << "-------------------------------------------------------------------------------------------------\n"; + os << '\n'; +} + +/// decodeARMInstruction is a decorator function which tries special cases of +/// instruction matching before calling the auto-generated decoder function. +static unsigned decodeARMInstruction(uint32_t &insn) { + if (slice(insn, 31, 28) == 15) + goto AutoGenedDecoder; + + // Special case processing, if any, goes here.... + + // LLVM combines the offset mode of A8.6.197 & A8.6.198 into STRB. + // The insufficient encoding information of the combined instruction confuses + // the decoder wrt BFC/BFI. Therefore, we try to recover here. + // For BFC, Inst{27-21} = 0b0111110 & Inst{6-0} = 0b0011111. + // For BFI, Inst{27-21} = 0b0111110 & Inst{6-4} = 0b001 & Inst{3-0} =! 0b1111. + if (slice(insn, 27, 21) == 0x3e && slice(insn, 6, 4) == 1) { + if (slice(insn, 3, 0) == 15) + return ARM::BFC; + else + return ARM::BFI; + } + + // Ditto for ADDSrs, which is a super-instruction for A8.6.7 & A8.6.8. + // As a result, the decoder fails to decode UMULL properly. + if (slice(insn, 27, 21) == 0x04 && slice(insn, 7, 4) == 9) { + return ARM::UMULL; + } + + // Ditto for STR_PRE, which is a super-instruction for A8.6.194 & A8.6.195. + // As a result, the decoder fails to decode SBFX properly. + if (slice(insn, 27, 21) == 0x3d && slice(insn, 6, 4) == 5) + return ARM::SBFX; + + // And STRB_PRE, which is a super-instruction for A8.6.197 & A8.6.198. + // As a result, the decoder fails to decode UBFX properly. + if (slice(insn, 27, 21) == 0x3f && slice(insn, 6, 4) == 5) + return ARM::UBFX; + + // Ditto for STRT, which is a super-instruction for A8.6.210 Encoding A1 & A2. + // As a result, the decoder fails to deocode SSAT properly. + if (slice(insn, 27, 21) == 0x35 && slice(insn, 5, 4) == 1) + return slice(insn, 6, 6) == 0 ? ARM::SSATlsl : ARM::SSATasr; + + // Ditto for RSCrs, which is a super-instruction for A8.6.146 & A8.6.147. + // As a result, the decoder fails to decode STRHT/LDRHT/LDRSHT/LDRSBT. + if (slice(insn, 27, 24) == 0) { + switch (slice(insn, 21, 20)) { + case 2: + switch (slice(insn, 7, 4)) { + case 11: + return ARM::STRHT; + default: + break; // fallthrough + } + break; + case 3: + switch (slice(insn, 7, 4)) { + case 11: + return ARM::LDRHT; + case 13: + return ARM::LDRSBT; + case 15: + return ARM::LDRSHT; + default: + break; // fallthrough + } + break; + default: + break; // fallthrough + } + } + + // Ditto for SBCrs, which is a super-instruction for A8.6.152 & A8.6.153. + // As a result, the decoder fails to decode STRH_Post/LDRD_POST/STRD_POST + // properly. + if (slice(insn, 27, 25) == 0 && slice(insn, 20, 20) == 0) { + unsigned PW = slice(insn, 24, 24) << 1 | slice(insn, 21, 21); + switch (slice(insn, 7, 4)) { + case 11: + switch (PW) { + case 2: // Offset + return ARM::STRH; + case 3: // Pre-indexed + return ARM::STRH_PRE; + case 0: // Post-indexed + return ARM::STRH_POST; + default: + break; // fallthrough + } + break; + case 13: + switch (PW) { + case 2: // Offset + return ARM::LDRD; + case 3: // Pre-indexed + return ARM::LDRD_PRE; + case 0: // Post-indexed + return ARM::LDRD_POST; + default: + break; // fallthrough + } + break; + case 15: + switch (PW) { + case 2: // Offset + return ARM::STRD; + case 3: // Pre-indexed + return ARM::STRD_PRE; + case 0: // Post-indexed + return ARM::STRD_POST; + default: + break; // fallthrough + } + break; + default: + break; // fallthrough + } + } + + // Ditto for SBCSSrs, which is a super-instruction for A8.6.152 & A8.6.153. + // As a result, the decoder fails to decode LDRH_POST/LDRSB_POST/LDRSH_POST + // properly. + if (slice(insn, 27, 25) == 0 && slice(insn, 20, 20) == 1) { + unsigned PW = slice(insn, 24, 24) << 1 | slice(insn, 21, 21); + switch (slice(insn, 7, 4)) { + case 11: + switch (PW) { + case 2: // Offset + return ARM::LDRH; + case 3: // Pre-indexed + return ARM::LDRH_PRE; + case 0: // Post-indexed + return ARM::LDRH_POST; + default: + break; // fallthrough + } + break; + case 13: + switch (PW) { + case 2: // Offset + return ARM::LDRSB; + case 3: // Pre-indexed + return ARM::LDRSB_PRE; + case 0: // Post-indexed + return ARM::LDRSB_POST; + default: + break; // fallthrough + } + break; + case 15: + switch (PW) { + case 2: // Offset + return ARM::LDRSH; + case 3: // Pre-indexed + return ARM::LDRSH_PRE; + case 0: // Post-indexed + return ARM::LDRSH_POST; + default: + break; // fallthrough + } + break; + default: + break; // fallthrough + } + } + +AutoGenedDecoder: + // Calling the auto-generated decoder function. + return decodeInstruction(insn); +} + +// Helper function for special case handling of LDR (literal) and friends. +// See, for example, A6.3.7 Load word: Table A6-18 Load word. +// See A8.6.57 T3, T4 & A8.6.60 T2 and friends for why we morphed the opcode +// before passing it on. +static unsigned T2Morph2LoadLiteral(unsigned Opcode) { + switch (Opcode) { + default: + return Opcode; // Return unmorphed opcode. + + case ARM::t2LDRDi8: + return ARM::t2LDRDpci; + + case ARM::t2LDR_POST: case ARM::t2LDR_PRE: + case ARM::t2LDRi12: case ARM::t2LDRi8: + case ARM::t2LDRs: + return ARM::t2LDRpci; + + case ARM::t2LDRB_POST: case ARM::t2LDRB_PRE: + case ARM::t2LDRBi12: case ARM::t2LDRBi8: + case ARM::t2LDRBs: + return ARM::t2LDRBpci; + + case ARM::t2LDRH_POST: case ARM::t2LDRH_PRE: + case ARM::t2LDRHi12: case ARM::t2LDRHi8: + case ARM::t2LDRHs: + return ARM::t2LDRHpci; + + case ARM::t2LDRSB_POST: case ARM::t2LDRSB_PRE: + case ARM::t2LDRSBi12: case ARM::t2LDRSBi8: + case ARM::t2LDRSBs: + return ARM::t2LDRSBpci; + + case ARM::t2LDRSH_POST: case ARM::t2LDRSH_PRE: + case ARM::t2LDRSHi12: case ARM::t2LDRSHi8: + case ARM::t2LDRSHs: + return ARM::t2LDRSHpci; + } +} + +/// decodeThumbSideEffect is a decorator function which can potentially twiddle +/// the instruction or morph the returned opcode under Thumb2. +/// +/// First it checks whether the insn is a NEON or VFP instr; if true, bit +/// twiddling could be performed on insn to turn it into an ARM NEON/VFP +/// equivalent instruction and decodeInstruction is called with the transformed +/// insn. +/// +/// Next, there is special handling for Load byte/halfword/word instruction by +/// checking whether Rn=0b1111 and call T2Morph2LoadLiteral() on the decoded +/// Thumb2 instruction. See comments below for further details. +/// +/// Finally, one last check is made to see whether the insn is a NEON/VFP and +/// decodeInstruction(insn) is invoked on the original insn. +/// +/// Otherwise, decodeThumbInstruction is called with the original insn. +static unsigned decodeThumbSideEffect(bool IsThumb2, uint32_t &insn) { + if (IsThumb2) { + uint16_t op1 = slice(insn, 28, 27); + uint16_t op2 = slice(insn, 26, 20); + + // A6.3 32-bit Thumb instruction encoding + // Table A6-9 32-bit Thumb instruction encoding + + // The coprocessor instructions of interest are transformed to their ARM + // equivalents. + + // --------- Transform Begin Marker --------- + if ((op1 == 1 || op1 == 3) && slice(op2, 6, 4) == 7) { + // A7.4 Advanced SIMD data-processing instructions + // U bit of Thumb corresponds to Inst{24} of ARM. + uint16_t U = slice(op1, 1, 1); + + // Inst{28-24} of ARM = {1,0,0,1,U}; + uint16_t bits28_24 = 9 << 1 | U; + DEBUG(showBitVector(errs(), insn)); + setSlice(insn, 28, 24, bits28_24); + return decodeInstruction(insn); + } + + if (op1 == 3 && slice(op2, 6, 4) == 1 && slice(op2, 0, 0) == 0) { + // A7.7 Advanced SIMD element or structure load/store instructions + // Inst{27-24} of Thumb = 0b1001 + // Inst{27-24} of ARM = 0b0100 + DEBUG(showBitVector(errs(), insn)); + setSlice(insn, 27, 24, 4); + return decodeInstruction(insn); + } + // --------- Transform End Marker --------- + + // See, for example, A6.3.7 Load word: Table A6-18 Load word. + // See A8.6.57 T3, T4 & A8.6.60 T2 and friends for why we morphed the opcode + // before passing it on to our delegate. + if (op1 == 3 && slice(op2, 6, 5) == 0 && slice(op2, 0, 0) == 1 + && slice(insn, 19, 16) == 15) + return T2Morph2LoadLiteral(decodeThumbInstruction(insn)); + + // One last check for NEON/VFP instructions. + if ((op1 == 1 || op1 == 3) && slice(op2, 6, 6) == 1) + return decodeInstruction(insn); + + // Fall through. + } + + return decodeThumbInstruction(insn); +} + +static inline bool Thumb2PreloadOpcodeNoPCI(unsigned Opcode) { + switch (Opcode) { + default: + return false; + case ARM::t2PLDi12: case ARM::t2PLDi8: + case ARM::t2PLDr: case ARM::t2PLDs: + case ARM::t2PLDWi12: case ARM::t2PLDWi8: + case ARM::t2PLDWr: case ARM::t2PLDWs: + case ARM::t2PLIi12: case ARM::t2PLIi8: + case ARM::t2PLIr: case ARM::t2PLIs: + return true; + } +} + +static inline unsigned T2Morph2Preload2PCI(unsigned Opcode) { + switch (Opcode) { + default: + return 0; + case ARM::t2PLDi12: case ARM::t2PLDi8: + case ARM::t2PLDr: case ARM::t2PLDs: + return ARM::t2PLDpci; + case ARM::t2PLDWi12: case ARM::t2PLDWi8: + case ARM::t2PLDWr: case ARM::t2PLDWs: + return ARM::t2PLDWpci; + case ARM::t2PLIi12: case ARM::t2PLIi8: + case ARM::t2PLIr: case ARM::t2PLIs: + return ARM::t2PLIpci; + } +} + +// +// Public interface for the disassembler +// + +bool ARMDisassembler::getInstruction(MCInst &MI, + uint64_t &Size, + const MemoryObject &Region, + uint64_t Address, + raw_ostream &os) const { + // The machine instruction. + uint32_t insn; + + // We want to read exactly 4 bytes of data. + if (Region.readBytes(Address, 4, (uint8_t*)&insn, NULL) == -1) + return false; + + unsigned Opcode = decodeARMInstruction(insn); + ARMFormat Format = ARMFormats[Opcode]; + NSFormat NSF = NSFormats[Opcode]; + Size = 4; + + DEBUG({ + errs() << "Opcode=" << Opcode << " Name=" << ARMUtils::OpcodeName(Opcode) + << " Format=" << stringForARMFormat(Format) << " NSFormat=" + << stringForNSFormat(NSF) << '\n'; + showBitVector(errs(), insn); + }); + + AbstractARMMCBuilder *Builder = + ARMMCBuilderFactory::CreateMCBuilder(Opcode, Format, NSF); + + if (!Builder) + return false; + + if (!Builder->Build(MI, insn)) + return false; + + delete Builder; + + return true; +} + +bool ThumbDisassembler::getInstruction(MCInst &MI, + uint64_t &Size, + const MemoryObject &Region, + uint64_t Address, + raw_ostream &os) const { + // The machine instruction. + uint32_t insn = 0; + uint32_t insn1 = 0; + + // A6.1 Thumb instruction set encoding + // + // If bits [15:11] of the halfword being decoded take any of the following + // values, the halfword is the first halfword of a 32-bit instruction: + // o 0b11101 + // o 0b11110 + // o 0b11111. + // + // Otherwise, the halfword is a 16-bit instruction. + + // Read 2 bytes of data first. + if (Region.readBytes(Address, 2, (uint8_t*)&insn, NULL) == -1) + return false; + + unsigned bits15_11 = slice(insn, 15, 11); + bool IsThumb2 = false; + + // 32-bit instructions if the bits [15:11] of the halfword matches + // { 0b11101 /* 0x1D */, 0b11110 /* 0x1E */, ob11111 /* 0x1F */ }. + if (bits15_11 == 0x1D || bits15_11 == 0x1E || bits15_11 == 0x1F) { + IsThumb2 = true; + if (Region.readBytes(Address + 2, 2, (uint8_t*)&insn1, NULL) == -1) + return false; + insn = (insn << 16 | insn1); + } + + // The insn could potentially be bit-twiddled in order to be decoded as an ARM + // NEON/VFP opcode. In such case, the modified insn is later disassembled as + // an ARM NEON/VFP instruction. + // + // This is a short term solution for lack of encoding bits specified for the + // Thumb2 NEON/VFP instructions. The long term solution could be adding some + // infrastructure to have each instruction support more than one encodings. + // Which encoding is used would be based on which subtarget the compiler/ + // disassembler is working with at the time. This would allow the sharing of + // the NEON patterns between ARM and Thumb2, as well as potential greater + // sharing between the regular ARM instructions and the 32-bit wide Thumb2 + // instructions as well. + unsigned Opcode = decodeThumbSideEffect(IsThumb2, insn); + + // A8.6.117/119/120/121. + // PLD/PLDW/PLI instructions with Rn==15 is transformed to the pci variant. + if (Thumb2PreloadOpcodeNoPCI(Opcode) && slice(insn, 19, 16) == 15) + Opcode = T2Morph2Preload2PCI(Opcode); + + ARMFormat Format = ARMFormats[Opcode]; + NSFormat NSF = NSFormats[Opcode]; + Size = IsThumb2 ? 4 : 2; + + DEBUG({ + errs() << "Opcode=" << Opcode << " Name=" << ARMUtils::OpcodeName(Opcode) + << " Format=" << stringForARMFormat(Format) << " NSFormat=" + << stringForNSFormat(NSF) << '\n'; + showBitVector(errs(), insn); + }); + + AbstractARMMCBuilder *Builder = + ARMMCBuilderFactory::CreateMCBuilder(Opcode, Format, NSF); + + if (!Builder) + return false; + + if (!Builder->Build(MI, insn)) + return false; + + delete Builder; + + return true; +} + +} // namespace ARM Disassembler + +static const MCDisassembler *createARMDisassembler(const Target &T) { + return new ARMDisassembler::ARMDisassembler; +} + +static const MCDisassembler *createThumbDisassembler(const Target &T) { + return new ARMDisassembler::ThumbDisassembler; +} + +extern "C" void LLVMInitializeARMDisassembler() { + // Register the disassembler. + TargetRegistry::RegisterMCDisassembler(TheARMTarget, + createARMDisassembler); + TargetRegistry::RegisterMCDisassembler(TheThumbTarget, + createThumbDisassembler); +} + +} // namespace llvm Added: llvm/trunk/lib/Target/ARM/Disassembler/ARMDisassembler.h URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Target/ARM/Disassembler/ARMDisassembler.h?rev=98637&view=auto ============================================================================== --- llvm/trunk/lib/Target/ARM/Disassembler/ARMDisassembler.h (added) +++ llvm/trunk/lib/Target/ARM/Disassembler/ARMDisassembler.h Tue Mar 16 11:36:54 2010 @@ -0,0 +1,71 @@ +//===- X86Disassembler.h - Disassembler for x86 and x86_64 ------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +//===----------------------------------------------------------------------===// + +#ifndef ARMDISASSEMBLER_H +#define ARMDISASSEMBLER_H + +#include "llvm/MC/MCDisassembler.h" + +namespace llvm { + +class MCInst; +class MemoryObject; +class raw_ostream; + +namespace ARMDisassembler { + +/// ARMDisassembler - ARM disassembler for all ARM platforms. +class ARMDisassembler : public MCDisassembler { +public: + /// Constructor - Initializes the disassembler. + /// + ARMDisassembler() : + MCDisassembler() { + } + + ~ARMDisassembler() { + } + + /// getInstruction - See MCDisassembler. + bool getInstruction(MCInst &instr, + uint64_t &size, + const MemoryObject ®ion, + uint64_t address, + raw_ostream &vStream) const; +private: +}; + +/// ThumbDisassembler - Thumb disassembler for all ARM platforms. +class ThumbDisassembler : public MCDisassembler { +public: + /// Constructor - Initializes the disassembler. + /// + ThumbDisassembler() : + MCDisassembler() { + } + + ~ThumbDisassembler() { + } + + /// getInstruction - See MCDisassembler. + bool getInstruction(MCInst &instr, + uint64_t &size, + const MemoryObject ®ion, + uint64_t address, + raw_ostream &vStream) const; +private: +}; + +} // namespace ARMDisassembler + +} // namespace llvm + +#endif Added: llvm/trunk/lib/Target/ARM/Disassembler/ARMDisassemblerCore.cpp URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Target/ARM/Disassembler/ARMDisassemblerCore.cpp?rev=98637&view=auto ============================================================================== --- llvm/trunk/lib/Target/ARM/Disassembler/ARMDisassemblerCore.cpp (added) +++ llvm/trunk/lib/Target/ARM/Disassembler/ARMDisassemblerCore.cpp Tue Mar 16 11:36:54 2010 @@ -0,0 +1,3351 @@ +//===- ARMDisassemblerCore.cpp - ARM disassembler helpers ----*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file is part of the ARM Disassembler. +// It contains code to represent the core concepts of Builder, Builder Factory, +// as well as the Algorithm to solve the problem of disassembling an ARM instr. +// +//===----------------------------------------------------------------------===// + +#include "ARMAddressingModes.h" +#include "ARMDisassemblerCore.h" +#include + +/// ARMGenInstrInfo.inc - ARMGenInstrInfo.inc contains the static const +/// TargetInstrDesc ARMInsts[] definition and the TargetOperandInfo[]'s +/// describing the operand info for each ARMInsts[i]. +/// +/// Together with an instruction's encoding format, we can take advantage of the +/// NumOperands and the OpInfo fields of the target instruction description in +/// the quest to build out the MCOperand list for an MCInst. +/// +/// The general guideline is that with a known format, the number of dst and src +/// operands are well-known. The dst is built first, followed by the src +/// operand(s). The operands not yet used at this point are for the Implicit +/// Uses and Defs by this instr. For the Uses part, the pred:$p operand is +/// defined with two components: +/// +/// def pred { // Operand PredicateOperand +/// ValueType Type = OtherVT; +/// string PrintMethod = "printPredicateOperand"; +/// string AsmOperandLowerMethod = ?; +/// dag MIOperandInfo = (ops i32imm, CCR); +/// AsmOperandClass ParserMatchClass = ImmAsmOperand; +/// dag DefaultOps = (ops (i32 14), (i32 zero_reg)); +/// } +/// +/// which is manifested by the TargetOperandInfo[] of: +/// +/// { 0, 0|(1<> 1 : RawRegister; + + switch (RegNum) { + default: + break; + case 0: + switch (RegClassID) { + case ARM::GPRRegClassID: case ARM::tGPRRegClassID: return ARM::R0; + case ARM::DPRRegClassID: case ARM::DPR_8RegClassID: + case ARM::DPR_VFP2RegClassID: + return ARM::D0; + case ARM::QPRRegClassID: case ARM::QPR_8RegClassID: + case ARM::QPR_VFP2RegClassID: + return ARM::Q0; + case ARM::SPRRegClassID: case ARM::SPR_8RegClassID: return ARM::S0; + } + break; + case 1: + switch (RegClassID) { + case ARM::GPRRegClassID: case ARM::tGPRRegClassID: return ARM::R1; + case ARM::DPRRegClassID: case ARM::DPR_8RegClassID: + case ARM::DPR_VFP2RegClassID: + return ARM::D1; + case ARM::QPRRegClassID: case ARM::QPR_8RegClassID: + case ARM::QPR_VFP2RegClassID: + return ARM::Q1; + case ARM::SPRRegClassID: case ARM::SPR_8RegClassID: return ARM::S1; + } + break; + case 2: + switch (RegClassID) { + case ARM::GPRRegClassID: case ARM::tGPRRegClassID: return ARM::R2; + case ARM::DPRRegClassID: case ARM::DPR_8RegClassID: + case ARM::DPR_VFP2RegClassID: + return ARM::D2; + case ARM::QPRRegClassID: case ARM::QPR_8RegClassID: + case ARM::QPR_VFP2RegClassID: + return ARM::Q2; + case ARM::SPRRegClassID: case ARM::SPR_8RegClassID: return ARM::S2; + } + break; + case 3: + switch (RegClassID) { + case ARM::GPRRegClassID: case ARM::tGPRRegClassID: return ARM::R3; + case ARM::DPRRegClassID: case ARM::DPR_8RegClassID: + case ARM::DPR_VFP2RegClassID: + return ARM::D3; + case ARM::QPRRegClassID: case ARM::QPR_8RegClassID: + case ARM::QPR_VFP2RegClassID: + return ARM::Q3; + case ARM::SPRRegClassID: case ARM::SPR_8RegClassID: return ARM::S3; + } + break; + case 4: + switch (RegClassID) { + case ARM::GPRRegClassID: case ARM::tGPRRegClassID: return ARM::R4; + case ARM::DPRRegClassID: case ARM::DPR_8RegClassID: + case ARM::DPR_VFP2RegClassID: + return ARM::D4; + case ARM::QPRRegClassID: case ARM::QPR_VFP2RegClassID: return ARM::Q4; + case ARM::SPRRegClassID: case ARM::SPR_8RegClassID: return ARM::S4; + } + break; + case 5: + switch (RegClassID) { + case ARM::GPRRegClassID: case ARM::tGPRRegClassID: return ARM::R5; + case ARM::DPRRegClassID: case ARM::DPR_8RegClassID: + case ARM::DPR_VFP2RegClassID: + return ARM::D5; + case ARM::QPRRegClassID: case ARM::QPR_VFP2RegClassID: return ARM::Q5; + case ARM::SPRRegClassID: case ARM::SPR_8RegClassID: return ARM::S5; + } + break; + case 6: + switch (RegClassID) { + case ARM::GPRRegClassID: case ARM::tGPRRegClassID: return ARM::R6; + case ARM::DPRRegClassID: case ARM::DPR_8RegClassID: + case ARM::DPR_VFP2RegClassID: + return ARM::D6; + case ARM::QPRRegClassID: case ARM::QPR_VFP2RegClassID: return ARM::Q6; + case ARM::SPRRegClassID: case ARM::SPR_8RegClassID: return ARM::S6; + } + break; + case 7: + switch (RegClassID) { + case ARM::GPRRegClassID: case ARM::tGPRRegClassID: return ARM::R7; + case ARM::DPRRegClassID: case ARM::DPR_8RegClassID: + case ARM::DPR_VFP2RegClassID: + return ARM::D7; + case ARM::QPRRegClassID: case ARM::QPR_VFP2RegClassID: return ARM::Q7; + case ARM::SPRRegClassID: case ARM::SPR_8RegClassID: return ARM::S7; + } + break; + case 8: + switch (RegClassID) { + case ARM::GPRRegClassID: return ARM::R8; + case ARM::DPRRegClassID: case ARM::DPR_VFP2RegClassID: return ARM::D8; + case ARM::QPRRegClassID: return ARM::Q8; + case ARM::SPRRegClassID: case ARM::SPR_8RegClassID: return ARM::S8; + } + break; + case 9: + switch (RegClassID) { + case ARM::GPRRegClassID: return ARM::R9; + case ARM::DPRRegClassID: case ARM::DPR_VFP2RegClassID: return ARM::D9; + case ARM::QPRRegClassID: return ARM::Q9; + case ARM::SPRRegClassID: case ARM::SPR_8RegClassID: return ARM::S9; + } + break; + case 10: + switch (RegClassID) { + case ARM::GPRRegClassID: return ARM::R10; + case ARM::DPRRegClassID: case ARM::DPR_VFP2RegClassID: return ARM::D10; + case ARM::QPRRegClassID: return ARM::Q10; + case ARM::SPRRegClassID: case ARM::SPR_8RegClassID: return ARM::S10; + } + break; + case 11: + switch (RegClassID) { + case ARM::GPRRegClassID: return ARM::R11; + case ARM::DPRRegClassID: case ARM::DPR_VFP2RegClassID: return ARM::D11; + case ARM::QPRRegClassID: return ARM::Q11; + case ARM::SPRRegClassID: case ARM::SPR_8RegClassID: return ARM::S11; + } + break; + case 12: + switch (RegClassID) { + case ARM::GPRRegClassID: return ARM::R12; + case ARM::DPRRegClassID: case ARM::DPR_VFP2RegClassID: return ARM::D12; + case ARM::QPRRegClassID: return ARM::Q12; + case ARM::SPRRegClassID: case ARM::SPR_8RegClassID: return ARM::S12; + } + break; + case 13: + switch (RegClassID) { + case ARM::GPRRegClassID: return ARM::SP; + case ARM::DPRRegClassID: case ARM::DPR_VFP2RegClassID: return ARM::D13; + case ARM::QPRRegClassID: return ARM::Q13; + case ARM::SPRRegClassID: case ARM::SPR_8RegClassID: return ARM::S13; + } + break; + case 14: + switch (RegClassID) { + case ARM::GPRRegClassID: return ARM::LR; + case ARM::DPRRegClassID: case ARM::DPR_VFP2RegClassID: return ARM::D14; + case ARM::QPRRegClassID: return ARM::Q14; + case ARM::SPRRegClassID: case ARM::SPR_8RegClassID: return ARM::S14; + } + break; + case 15: + switch (RegClassID) { + case ARM::GPRRegClassID: return ARM::PC; + case ARM::DPRRegClassID: case ARM::DPR_VFP2RegClassID: return ARM::D15; + case ARM::QPRRegClassID: return ARM::Q15; + case ARM::SPRRegClassID: case ARM::SPR_8RegClassID: return ARM::S15; + } + break; + case 16: + switch (RegClassID) { + case ARM::DPRRegClassID: return ARM::D16; + case ARM::SPRRegClassID: return ARM::S16; + } + break; + case 17: + switch (RegClassID) { + case ARM::DPRRegClassID: return ARM::D17; + case ARM::SPRRegClassID: return ARM::S17; + } + break; + case 18: + switch (RegClassID) { + case ARM::DPRRegClassID: return ARM::D18; + case ARM::SPRRegClassID: return ARM::S18; + } + break; + case 19: + switch (RegClassID) { + case ARM::DPRRegClassID: return ARM::D19; + case ARM::SPRRegClassID: return ARM::S19; + } + break; + case 20: + switch (RegClassID) { + case ARM::DPRRegClassID: return ARM::D20; + case ARM::SPRRegClassID: return ARM::S20; + } + break; + case 21: + switch (RegClassID) { + case ARM::DPRRegClassID: return ARM::D21; + case ARM::SPRRegClassID: return ARM::S21; + } + break; + case 22: + switch (RegClassID) { + case ARM::DPRRegClassID: return ARM::D22; + case ARM::SPRRegClassID: return ARM::S22; + } + break; + case 23: + switch (RegClassID) { + case ARM::DPRRegClassID: return ARM::D23; + case ARM::SPRRegClassID: return ARM::S23; + } + break; + case 24: + switch (RegClassID) { + case ARM::DPRRegClassID: return ARM::D24; + case ARM::SPRRegClassID: return ARM::S24; + } + break; + case 25: + switch (RegClassID) { + case ARM::DPRRegClassID: return ARM::D25; + case ARM::SPRRegClassID: return ARM::S25; + } + break; + case 26: + switch (RegClassID) { + case ARM::DPRRegClassID: return ARM::D26; + case ARM::SPRRegClassID: return ARM::S26; + } + break; + case 27: + switch (RegClassID) { + case ARM::DPRRegClassID: return ARM::D27; + case ARM::SPRRegClassID: return ARM::S27; + } + break; + case 28: + switch (RegClassID) { + case ARM::DPRRegClassID: return ARM::D28; + case ARM::SPRRegClassID: return ARM::S28; + } + break; + case 29: + switch (RegClassID) { + case ARM::DPRRegClassID: return ARM::D29; + case ARM::SPRRegClassID: return ARM::S29; + } + break; + case 30: + switch (RegClassID) { + case ARM::DPRRegClassID: return ARM::D30; + case ARM::SPRRegClassID: return ARM::S30; + } + break; + case 31: + switch (RegClassID) { + case ARM::DPRRegClassID: return ARM::D31; + case ARM::SPRRegClassID: return ARM::S31; + } + break; + } + llvm_unreachable("Invalid (RegClassID, RawRegister) combination"); +} + +// This is efficient but fragile. +/* +// See ARMGenRegisterInfo.h.inc for more info. +static const TargetRegisterClass* const ARMRegisterClasses[] = { + NULL, + &ARM::CCRRegClass, // CCRRegClassID = 1, + &ARM::DPRRegClass, // DPRRegClassID = 2, + &ARM::DPR_8RegClass, // DPR_8RegClassID = 3, + &ARM::DPR_VFP2RegClass, // DPR_VFP2RegClassID = 4, + &ARM::GPRRegClass, // GPRRegClassID = 5, + &ARM::QPRRegClass, // QPRRegClassID = 6, + &ARM::QPR_8RegClass, // QPR_8RegClassID = 7, + &ARM::QPR_VFP2RegClass, // QPR_VFP2RegClassID = 8, + &ARM::SPRRegClass, // SPRRegClassID = 9, + &ARM::SPR_8RegClass, // SPR_8RegClassID = 10, + &ARM::SPR_INVALIDRegClass, // SPR_INVALIDRegClassID = 11, + &ARM::tGPRRegClass, // tGPRRegClassID = 12 +}; + +// Return the register enum given register class id and raw register value. +static unsigned getRegisterEnum(unsigned RegClassID, unsigned RawRegister) { + assert(RegClassID < array_lengthof(ARMRegisterClasses) && + "Register Class ID out of range"); + return ARMRegisterClasses[RegClassID]->getRegister(RawRegister); +} +*/ + +/// DisassembleFP - DisassembleFP points to a function that disassembles an insn +/// and builds the MCOperand list upon disassembly. It returns false on failure +/// or true on success. The number of operands added is updated upon success. +typedef bool (*DisassembleFP)(MCInst &MI, unsigned Opcode, uint32_t insn, + unsigned short NumOps, unsigned &NumOpsAdded); + +/////////////////////////////// +// // +// Utility Functions // +// // +/////////////////////////////// + +// Extract/Decode Rd: Inst{15-12}. +static inline unsigned decodeRd(uint32_t insn) { + return (insn >> ARMII::RegRdShift) & ARMII::GPRRegMask; +} + +// Extract/Decode Rn: Inst{19-16}. +static inline unsigned decodeRn(uint32_t insn) { + return (insn >> ARMII::RegRnShift) & ARMII::GPRRegMask; +} + +// Extract/Decode Rm: Inst{3-0}. +static inline unsigned decodeRm(uint32_t insn) { + return (insn & ARMII::GPRRegMask); +} + +// Extract/Decode Rs: Inst{11-8}. +static inline unsigned decodeRs(uint32_t insn) { + return (insn >> ARMII::RegRsShift) & ARMII::GPRRegMask; +} + +static inline unsigned getCondField(uint32_t insn) { + return (insn >> ARMII::CondShift); +} + +static inline unsigned getIBit(uint32_t insn) { + return (insn >> ARMII::I_BitShift) & 1; +} + +static inline unsigned getAM3IBit(uint32_t insn) { + return (insn >> ARMII::AM3_I_BitShift) & 1; +} + +static inline unsigned getPBit(uint32_t insn) { + return (insn >> ARMII::P_BitShift) & 1; +} + +static inline unsigned getUBit(uint32_t insn) { + return (insn >> ARMII::U_BitShift) & 1; +} + +static inline unsigned getPUBits(uint32_t insn) { + return (insn >> ARMII::U_BitShift) & 3; +} + +static inline unsigned getSBit(uint32_t insn) { + return (insn >> ARMII::S_BitShift) & 1; +} + +static inline unsigned getWBit(uint32_t insn) { + return (insn >> ARMII::W_BitShift) & 1; +} + +static inline unsigned getDBit(uint32_t insn) { + return (insn >> ARMII::D_BitShift) & 1; +} + +static inline unsigned getNBit(uint32_t insn) { + return (insn >> ARMII::N_BitShift) & 1; +} + +static inline unsigned getMBit(uint32_t insn) { + return (insn >> ARMII::M_BitShift) & 1; +} + +namespace { +// Sign extend 5 bit number x to r. +// Usage: int r = signextend(x); +template inline T signextend(const T x) { + struct {T x:B;} s; + return s.x = x; +} +} + +// See A8.4 Shifts applied to a register. +// A8.4.2 Register controlled shifts. +// +// getShiftOpcForBits - getShiftOpcForBits translates from the ARM encoding bits +// into llvm enums for shift opcode. +// +// A8-12: DecodeRegShift() +static inline ARM_AM::ShiftOpc getShiftOpcForBits(unsigned bits) { + switch (bits) { + default: assert(0 && "No such value"); + case 0: return ARM_AM::lsl; + case 1: return ARM_AM::lsr; + case 2: return ARM_AM::asr; + case 3: return ARM_AM::ror; + } +} + +// See A8.4 Shifts applied to a register. +// A8.4.1 Constant shifts. +// +// getImmShiftSE - getImmShiftSE translates from the raw ShiftOpc and raw Imm5 +// encodings into the intended ShiftOpc and shift amount. +// +// A8-11: DecodeImmShift() +static inline void getImmShiftSE(ARM_AM::ShiftOpc &ShOp, unsigned &ShImm) { + // If type == 0b11 and imm5 == 0, we have an rrx, instead. + if (ShOp == ARM_AM::ror && ShImm == 0) + ShOp = ARM_AM::rrx; + // If (lsr or asr) and imm5 == 0, shift amount is 32. + if ((ShOp == ARM_AM::lsr || ShOp == ARM_AM::asr) && ShImm == 0) + ShImm = 32; +} + +// getAMSubModeForBits - getAMSubModeForBits translates from the ARM encoding +// bits Inst{24-23} (P(24) and U(23)) into llvm enums for AMSubMode. +static inline ARM_AM::AMSubMode getAMSubModeForBits(unsigned bits) { + switch (bits) { + default: assert(0 && "No such value"); + case 1: return ARM_AM::ia; // P=0 U=1 + case 3: return ARM_AM::ib; // P=1 U=1 + case 0: return ARM_AM::da; // P=0 U=0 + case 2: return ARM_AM::db; // P=1 U=0 + } +} + +//////////////////////////////////////////// +// // +// Disassemble function definitions // +// // +//////////////////////////////////////////// + +/// There is a separate Disassemble*Frm function entry for disassembly of an ARM +/// instr into a list of MCOperands in the appropriate order, with possible dst, +/// followed by possible src(s). +/// +/// The processing of the predicate, and the 'S' modifier bit, if MI modifies +/// the CPSR, is factored into ARMBasicMCBuilder's class method named +/// TryPredicateAndSBitModifier. + +static bool DisassemblePseudo(MCInst &MI, unsigned Opcode, uint32_t insn, + unsigned short NumOps, unsigned &NumOpsAdded) { + + if (Opcode == ARM::Int_MemBarrierV7 || Opcode == ARM::Int_SyncBarrierV7) + return true; + + assert(0 && "Unexpected pseudo instruction!"); + return false; +} + +// Multiply Instructions. +// MLA, MLS, SMLABB, SMLABT, SMLATB, SMLATT, SMLAWB, SMLAWT, SMMLA, SMMLS: +// Rd{19-16} Rn{3-0} Rm{11-8} Ra{15-12} +// +// MUL, SMMUL, SMULBB, SMULBT, SMULTB, SMULTT, SMULWB, SMULWT: +// Rd{19-16} Rn{3-0} Rm{11-8} +// +// SMLAL, SMULL, UMAAL, UMLAL, UMULL, SMLALBB, SMLALBT, SMLALTB, SMLALTT: +// RdLo{15-12} RdHi{19-16} Rn{3-0} Rm{11-8} +// +// The mapping of the multiply registers to the "regular" ARM registers, where +// there are convenience decoder functions, is: +// +// Inst{15-12} => Rd +// Inst{19-16} => Rn +// Inst{3-0} => Rm +// Inst{11-8} => Rs +static bool DisassembleMulFrm(MCInst &MI, unsigned Opcode, uint32_t insn, + unsigned short NumOps, unsigned &NumOpsAdded) { + + const TargetInstrDesc &TID = ARMInsts[Opcode]; + unsigned short NumDefs = TID.getNumDefs(); + const TargetOperandInfo *OpInfo = TID.OpInfo; + unsigned &OpIdx = NumOpsAdded; + + OpIdx = 0; + + assert(NumDefs > 0 && "NumDefs should be greater than 0 for MulFrm"); + assert(NumOps >= 3 + && OpInfo[0].RegClass == ARM::GPRRegClassID + && OpInfo[1].RegClass == ARM::GPRRegClassID + && OpInfo[2].RegClass == ARM::GPRRegClassID); + + // Instructions with two destination registers have RdLo{15-12} first. + if (NumDefs == 2) { + assert(NumOps >= 4 && OpInfo[3].RegClass == ARM::GPRRegClassID); + MI.addOperand(MCOperand::CreateReg(getRegisterEnum(ARM::GPRRegClassID, + decodeRd(insn)))); + ++OpIdx; + } + + // The destination register: RdHi{19-16} or Rd{19-16}. + MI.addOperand(MCOperand::CreateReg(getRegisterEnum(ARM::GPRRegClassID, + decodeRn(insn)))); + + // The two src regsiters: Rn{3-0}, then Rm{11-8}. + MI.addOperand(MCOperand::CreateReg(getRegisterEnum(ARM::GPRRegClassID, + decodeRm(insn)))); + MI.addOperand(MCOperand::CreateReg(getRegisterEnum(ARM::GPRRegClassID, + decodeRs(insn)))); + OpIdx += 3; + + // Many multiply instructions (e.g., MLA) have three src registers. + // The third register operand is Ra{15-12}. + if (OpIdx < NumOps && OpInfo[OpIdx].RegClass == ARM::GPRRegClassID) { + MI.addOperand(MCOperand::CreateReg(getRegisterEnum(ARM::GPRRegClassID, + decodeRd(insn)))); + ++OpIdx; + } + + return true; +} + +// Helper routines for disassembly of coprocessor instructions. + +static bool LdStCopOpcode(unsigned Opcode) { + if ((Opcode >= ARM::LDC2L_OFFSET && Opcode <= ARM::LDC_PRE) || + (Opcode >= ARM::STC2L_OFFSET && Opcode <= ARM::STC_PRE)) + return true; + return false; +} +static bool CoprocessorOpcode(unsigned Opcode) { + if (LdStCopOpcode(Opcode)) + return true; + + switch (Opcode) { + default: + return false; + case ARM::CDP: case ARM::CDP2: + case ARM::MCR: case ARM::MCR2: case ARM::MRC: case ARM::MRC2: + case ARM::MCRR: case ARM::MCRR2: case ARM::MRRC: case ARM::MRRC2: + return true; + } +} +static inline unsigned GetCoprocessor(uint32_t insn) { + return slice(insn, 11, 8); +} +static inline unsigned GetCopOpc1(uint32_t insn, bool CDP) { + return CDP ? slice(insn, 23, 20) : slice(insn, 23, 21); +} +static inline unsigned GetCopOpc2(uint32_t insn) { + return slice(insn, 7, 5); +} +static inline unsigned GetCopOpc(uint32_t insn) { + return slice(insn, 7, 4); +} +// Most of the operands are in immediate forms, except Rd and Rn, which are ARM +// core registers. +// +// CDP, CDP2: cop opc1 CRd CRn CRm opc2 +// +// MCR, MCR2, MRC, MRC2: cop opc1 Rd CRn CRm opc2 +// +// MCRR, MCRR2, MRRC, MRRc2: cop opc Rd Rn CRm +// +// LDC_OFFSET, LDC_PRE, LDC_POST: cop CRd Rn R0 [+/-]imm8:00 +// and friends +// STC_OFFSET, STC_PRE, STC_POST: cop CRd Rn R0 [+/-]imm8:00 +// and friends +// <-- addrmode2 --> +// +// LDC_OPTION: cop CRd Rn imm8 +// and friends +// STC_OPTION: cop CRd Rn imm8 +// and friends +// +static bool DisassembleCoprocessor(MCInst &MI, unsigned Opcode, uint32_t insn, + unsigned short NumOps, unsigned &NumOpsAdded) { + + assert(NumOps >= 5); + + unsigned &OpIdx = NumOpsAdded; + bool OneCopOpc = (Opcode == ARM::MCRR || Opcode == ARM::MCRR2 || + Opcode == ARM::MRRC || Opcode == ARM::MRRC2); + // CDP/CDP2 has no GPR operand; the opc1 operand is also wider (Inst{23-20}). + bool NoGPR = (Opcode == ARM::CDP || Opcode == ARM::CDP2); + bool LdStCop = LdStCopOpcode(Opcode); + + OpIdx = 0; + + MI.addOperand(MCOperand::CreateImm(GetCoprocessor(insn))); + + if (LdStCop) { + // Unindex if P:W = 0b00 --> _OPTION variant + unsigned PW = getPBit(insn) << 1 | getWBit(insn); + + MI.addOperand(MCOperand::CreateImm(decodeRd(insn))); + + MI.addOperand(MCOperand::CreateReg(getRegisterEnum(ARM::GPRRegClassID, + decodeRn(insn)))); + + if (PW) { + MI.addOperand(MCOperand::CreateReg(0)); + ARM_AM::AddrOpc AddrOpcode = getUBit(insn) ? ARM_AM::add : ARM_AM::sub; + unsigned Offset = ARM_AM::getAM2Opc(AddrOpcode, slice(insn, 7, 0) << 2, + ARM_AM::no_shift); + MI.addOperand(MCOperand::CreateImm(Offset)); + OpIdx = 5; + } else { + MI.addOperand(MCOperand::CreateImm(slice(insn, 7, 0))); + OpIdx = 4; + } + } else { + MI.addOperand(MCOperand::CreateImm(OneCopOpc ? GetCopOpc(insn) + : GetCopOpc1(insn, NoGPR))); + + MI.addOperand(NoGPR ? MCOperand::CreateImm(decodeRd(insn)) + : MCOperand::CreateReg( + getRegisterEnum(ARM::GPRRegClassID, + decodeRd(insn)))); + + MI.addOperand(OneCopOpc ? MCOperand::CreateReg( + getRegisterEnum(ARM::GPRRegClassID, + decodeRn(insn))) + : MCOperand::CreateImm(decodeRn(insn))); + + MI.addOperand(MCOperand::CreateImm(decodeRm(insn))); + + OpIdx = 5; + + if (!OneCopOpc) { + MI.addOperand(MCOperand::CreateImm(GetCopOpc2(insn))); + ++OpIdx; + } + } + + return true; +} + +// Branch Instructions. +// BLr9: SignExtend(Imm24:'00', 32) +// Bcc, BLr9_pred: SignExtend(Imm24:'00', 32) Pred0 Pred1 +// SMC: ZeroExtend(imm4, 32) +// SVC: ZeroExtend(Imm24, 32) +// +// Various coprocessor instructions are assigned BrFrm arbitrarily. +// Delegates to DisassembleCoprocessor() helper function. +// +// MRS/MRSsys: Rd +// MSR/MSRsys: Rm mask=Inst{19-16} +// BXJ: Rm +// MSRi/MSRsysi: so_imm +// SRSW/SRS: addrmode4:$addr mode_imm +// RFEW/RFE: addrmode4:$addr Rn +static bool DisassembleBrFrm(MCInst &MI, unsigned Opcode, uint32_t insn, + unsigned short NumOps, unsigned &NumOpsAdded) { + + if (CoprocessorOpcode(Opcode)) + return DisassembleCoprocessor(MI, Opcode, insn, NumOps, NumOpsAdded); + + const TargetOperandInfo *OpInfo = ARMInsts[Opcode].OpInfo; + + // MRS and MRSsys take one GPR reg Rd. + if (Opcode == ARM::MRS || Opcode == ARM::MRSsys) { + assert(NumOps >= 1 && OpInfo[0].RegClass == ARM::GPRRegClassID); + MI.addOperand(MCOperand::CreateReg(getRegisterEnum(ARM::GPRRegClassID, + decodeRd(insn)))); + NumOpsAdded = 1; + return true; + } + // BXJ takes one GPR reg Rm. + if (Opcode == ARM::BXJ) { + assert(NumOps >= 1 && OpInfo[0].RegClass == ARM::GPRRegClassID); + MI.addOperand(MCOperand::CreateReg(getRegisterEnum(ARM::GPRRegClassID, + decodeRm(insn)))); + NumOpsAdded = 1; + return true; + } + // MSR and MSRsys take one GPR reg Rm, followed by the mask. + if (Opcode == ARM::MSR || Opcode == ARM::MSRsys) { + assert(NumOps >= 1 && OpInfo[0].RegClass == ARM::GPRRegClassID); + MI.addOperand(MCOperand::CreateReg(getRegisterEnum(ARM::GPRRegClassID, + decodeRm(insn)))); + MI.addOperand(MCOperand::CreateImm(slice(insn, 19, 16))); + NumOpsAdded = 2; + return true; + } + // MSRi and MSRsysi take one so_imm operand, followed by the mask. + if (Opcode == ARM::MSRi || Opcode == ARM::MSRsysi) { + // SOImm is 4-bit rotate amount in bits 11-8 with 8-bit imm in bits 7-0. + // A5.2.4 Rotate amount is twice the numeric value of Inst{11-8}. + // See also ARMAddressingModes.h: getSOImmValImm() and getSOImmValRot(). + unsigned Rot = (insn >> ARMII::SoRotImmShift) & 0xF; + unsigned Imm = insn & 0xFF; + MI.addOperand(MCOperand::CreateImm(ARM_AM::rotr32(Imm, 2*Rot))); + MI.addOperand(MCOperand::CreateImm(slice(insn, 19, 16))); + NumOpsAdded = 2; + return true; + } + // SRSW and SRS requires addrmode4:$addr for ${addr:submode}, followed by the + // mode immediate (Inst{4-0}). + if (Opcode == ARM::SRSW || Opcode == ARM::SRS || + Opcode == ARM::RFEW || Opcode == ARM::RFE) { + // ARMInstPrinter::printAddrMode4Operand() prints special mode string + // if the base register is SP; so don't set ARM::SP. + MI.addOperand(MCOperand::CreateReg(0)); + bool WB = (Opcode == ARM::SRSW); + ARM_AM::AMSubMode SubMode = getAMSubModeForBits(getPUBits(insn)); + MI.addOperand(MCOperand::CreateImm(ARM_AM::getAM4ModeImm(SubMode, WB))); + + if (Opcode == ARM::SRSW || Opcode == ARM::SRS) + MI.addOperand(MCOperand::CreateImm(slice(insn, 4, 0))); + else + MI.addOperand(MCOperand::CreateReg(getRegisterEnum(ARM::GPRRegClassID, + decodeRn(insn)))); + NumOpsAdded = 3; + return true; + } + + assert(Opcode == ARM::Bcc || Opcode == ARM::BLr9 || Opcode == ARM::BLr9_pred + || Opcode == ARM::SMC || Opcode == ARM::SVC); + + assert(NumOps >= 1 && OpInfo[0].RegClass == 0); + + int Imm32 = 0; + if (Opcode == ARM::SMC) { + // ZeroExtend(imm4, 32) where imm24 = Inst{3-0}. + Imm32 = slice(insn, 3, 0); + } else if (Opcode == ARM::SVC) { + // ZeroExtend(imm24, 32) where imm24 = Inst{23-0}. + Imm32 = slice(insn, 23, 0); + } else { + // SignExtend(imm24:'00', 32) where imm24 = Inst{23-0}. + unsigned Imm26 = slice(insn, 23, 0) << 2; + Imm32 = signextend(Imm26); + + // When executing an ARM instruction, PC reads as the address of the current + // instruction plus 8. The assembler subtracts 8 from the difference + // between the branch instruction and the target address, disassembler has + // to add 8 to compensate. + Imm32 += 8; + } + + MI.addOperand(MCOperand::CreateImm(Imm32)); + NumOpsAdded = 1; + + return true; +} + +// Misc. Branch Instructions. +// BR_JTadd, BR_JTr, BR_JTm +// BLXr9, BXr9 +// BRIND, BX_RET +static bool DisassembleBrMiscFrm(MCInst &MI, unsigned Opcode, uint32_t insn, + unsigned short NumOps, unsigned &NumOpsAdded) { + + const TargetOperandInfo *OpInfo = ARMInsts[Opcode].OpInfo; + unsigned &OpIdx = NumOpsAdded; + + OpIdx = 0; + + // BX_RET has only two predicate operands, do an early return. + if (Opcode == ARM::BX_RET) + return true; + + // BLXr9 and BRIND take one GPR reg. + if (Opcode == ARM::BLXr9 || Opcode == ARM::BRIND) { + assert(NumOps >= 1 && OpInfo[OpIdx].RegClass == ARM::GPRRegClassID); + MI.addOperand(MCOperand::CreateReg(getRegisterEnum(ARM::GPRRegClassID, + decodeRm(insn)))); + OpIdx = 1; + return true; + } + + // BR_JTadd is an ADD with Rd = PC, (Rn, Rm) as the target and index regs. + if (Opcode == ARM::BR_JTadd) { + // InOperandList with GPR:$target and GPR:$idx regs. + + assert(NumOps == 4); + MI.addOperand(MCOperand::CreateReg(getRegisterEnum(ARM::GPRRegClassID, + decodeRn(insn)))); + MI.addOperand(MCOperand::CreateReg(getRegisterEnum(ARM::GPRRegClassID, + decodeRm(insn)))); + + // Fill in the two remaining imm operands to signify build completion. + MI.addOperand(MCOperand::CreateImm(0)); + MI.addOperand(MCOperand::CreateImm(0)); + + OpIdx = 4; + return true; + } + + // BR_JTr is a MOV with Rd = PC, and Rm as the source register. + if (Opcode == ARM::BR_JTr) { + // InOperandList with GPR::$target reg. + + assert(NumOps == 3); + MI.addOperand(MCOperand::CreateReg(getRegisterEnum(ARM::GPRRegClassID, + decodeRm(insn)))); + + // Fill in the two remaining imm operands to signify build completion. + MI.addOperand(MCOperand::CreateImm(0)); + MI.addOperand(MCOperand::CreateImm(0)); + + OpIdx = 3; + return true; + } + + // BR_JTm is an LDR with Rt = PC. + if (Opcode == ARM::BR_JTm) { + // This is the reg/reg form, with base reg followed by +/- reg shop imm. + // See also ARMAddressingModes.h (Addressing Mode #2). + + assert(NumOps == 5 && getIBit(insn) == 1); + MI.addOperand(MCOperand::CreateReg(getRegisterEnum(ARM::GPRRegClassID, + decodeRn(insn)))); + + ARM_AM::AddrOpc AddrOpcode = getUBit(insn) ? ARM_AM::add : ARM_AM::sub; + + // Disassemble the offset reg (Rm), shift type, and immediate shift length. + MI.addOperand(MCOperand::CreateReg(getRegisterEnum(ARM::GPRRegClassID, + decodeRm(insn)))); + // Inst{6-5} encodes the shift opcode. + ARM_AM::ShiftOpc ShOp = getShiftOpcForBits(slice(insn, 6, 5)); + // Inst{11-7} encodes the imm5 shift amount. + unsigned ShImm = slice(insn, 11, 7); + + // A8.4.1. Possible rrx or shift amount of 32... + getImmShiftSE(ShOp, ShImm); + MI.addOperand(MCOperand::CreateImm( + ARM_AM::getAM2Opc(AddrOpcode, ShImm, ShOp))); + + // Fill in the two remaining imm operands to signify build completion. + MI.addOperand(MCOperand::CreateImm(0)); + MI.addOperand(MCOperand::CreateImm(0)); + + OpIdx = 5; + return true; + } + + assert(0 && "Unexpected BrMiscFrm Opcode"); + return false; +} + +static inline uint32_t getBFCInvMask(uint32_t insn) { + uint32_t lsb = slice(insn, 11, 7); + uint32_t msb = slice(insn, 20, 16); + uint32_t Val = 0; + assert(lsb <= msb && "Encoding error: lsb > msb"); + for (uint32_t i = lsb; i <= msb; ++i) + Val |= (1 << i); + return ~Val; +} + +static inline bool SaturateOpcode(unsigned Opcode) { + switch (Opcode) { + case ARM::SSATlsl: case ARM::SSATasr: case ARM::SSAT16: + case ARM::USATlsl: case ARM::USATasr: case ARM::USAT16: + return true; + default: + return false; + } +} + +static inline unsigned decodeSaturatePos(unsigned Opcode, uint32_t insn) { + switch (Opcode) { + case ARM::SSATlsl: + case ARM::SSATasr: + return slice(insn, 20, 16) + 1; + case ARM::SSAT16: + return slice(insn, 19, 16) + 1; + case ARM::USATlsl: + case ARM::USATasr: + return slice(insn, 20, 16); + case ARM::USAT16: + return slice(insn, 19, 16); + default: + llvm_unreachable("Invalid opcode passed in"); + return 0; + } +} + +// A major complication is the fact that some of the saturating add/subtract +// operations have Rd Rm Rn, instead of the "normal" Rd Rn Rm. +// They are QADD, QDADD, QDSUB, and QSUB. +static bool DisassembleDPFrm(MCInst &MI, unsigned Opcode, uint32_t insn, + unsigned short NumOps, unsigned &NumOpsAdded) { + + const TargetInstrDesc &TID = ARMInsts[Opcode]; + unsigned short NumDefs = TID.getNumDefs(); + bool isUnary = isUnaryDP(TID.TSFlags); + const TargetOperandInfo *OpInfo = TID.OpInfo; + unsigned &OpIdx = NumOpsAdded; + + OpIdx = 0; + + // Disassemble register def if there is one. + if (NumDefs && (OpInfo[OpIdx].RegClass == ARM::GPRRegClassID)) { + MI.addOperand(MCOperand::CreateReg(getRegisterEnum(ARM::GPRRegClassID, + decodeRd(insn)))); + ++OpIdx; + } + + // Now disassemble the src operands. + if (OpIdx >= NumOps) + return false; + + // SSAT/SSAT16/USAT/USAT16 has imm operand after Rd. + if (SaturateOpcode(Opcode)) { + MI.addOperand(MCOperand::CreateImm(decodeSaturatePos(Opcode, insn))); + + MI.addOperand(MCOperand::CreateReg(getRegisterEnum(ARM::GPRRegClassID, + decodeRm(insn)))); + + if (Opcode == ARM::SSAT16 || Opcode == ARM::USAT16) { + OpIdx += 2; + return true; + } + + // For SSAT operand reg (Rm) has been disassembled above. + // Now disassemble the shift amount. + + // Inst{11-7} encodes the imm5 shift amount. + unsigned ShAmt = slice(insn, 11, 7); + + // A8.6.183. Possible ASR shift amount of 32... + if (Opcode == ARM::SSATasr && ShAmt == 0) + ShAmt = 32; + + MI.addOperand(MCOperand::CreateImm(ShAmt)); + + OpIdx += 3; + return true; + } + + // Special-case handling of BFC/BFI/SBFX/UBFX. + if (Opcode == ARM::BFC || Opcode == ARM::BFI) { + // TIED_TO operand skipped for BFC and Inst{3-0} (Reg) for BFI. + MI.addOperand(MCOperand::CreateReg(Opcode == ARM::BFC ? 0 + : getRegisterEnum(ARM::GPRRegClassID, + decodeRm(insn)))); + MI.addOperand(MCOperand::CreateImm(getBFCInvMask(insn))); + OpIdx += 2; + return true; + } + if (Opcode == ARM::SBFX || Opcode == ARM::UBFX) { + MI.addOperand(MCOperand::CreateReg(getRegisterEnum(ARM::GPRRegClassID, + decodeRm(insn)))); + MI.addOperand(MCOperand::CreateImm(slice(insn, 11, 7))); + MI.addOperand(MCOperand::CreateImm(slice(insn, 20, 16) + 1)); + OpIdx += 3; + return true; + } + + bool RmRn = (Opcode == ARM::QADD || Opcode == ARM::QDADD || + Opcode == ARM::QDSUB || Opcode == ARM::QSUB); + + // BinaryDP has an Rn operand. + if (!isUnary) { + assert(OpInfo[OpIdx].RegClass == ARM::GPRRegClassID); + MI.addOperand(MCOperand::CreateReg( + getRegisterEnum(ARM::GPRRegClassID, + RmRn ? decodeRm(insn) : decodeRn(insn)))); + ++OpIdx; + } + + // If this is a two-address operand, skip it, e.g., MOVCCr operand 1. + if (isUnary && (TID.getOperandConstraint(OpIdx, TOI::TIED_TO) != -1)) { + MI.addOperand(MCOperand::CreateReg(0)); + ++OpIdx; + } + + // Now disassemble operand 2. + if (OpIdx >= NumOps) + return false; + + if (OpInfo[OpIdx].RegClass == ARM::GPRRegClassID) { + // We have a reg/reg form. + // Assert disabled because saturating operations, e.g., A8.6.127 QASX, are + // routed here as well. + // assert(getIBit(insn) == 0 && "I_Bit != '0' reg/reg form"); + MI.addOperand(MCOperand::CreateReg( + getRegisterEnum(ARM::GPRRegClassID, + RmRn? decodeRn(insn) : decodeRm(insn)))); + ++OpIdx; + } else if (Opcode == ARM::MOVi16 || Opcode == ARM::MOVTi16) { + // We have an imm16 = imm4:imm12 (imm4=Inst{19:16}, imm12 = Inst{11:0}). + assert(getIBit(insn) == 1 && "I_Bit != '1' reg/imm form"); + unsigned Imm16 = slice(insn, 19, 16) << 12 | slice(insn, 11, 0); + MI.addOperand(MCOperand::CreateImm(Imm16)); + ++OpIdx; + } else { + // We have a reg/imm form. + // SOImm is 4-bit rotate amount in bits 11-8 with 8-bit imm in bits 7-0. + // A5.2.4 Rotate amount is twice the numeric value of Inst{11-8}. + // See also ARMAddressingModes.h: getSOImmValImm() and getSOImmValRot(). + assert(getIBit(insn) == 1 && "I_Bit != '1' reg/imm form"); + unsigned Rot = (insn >> ARMII::SoRotImmShift) & 0xF; + unsigned Imm = insn & 0xFF; + MI.addOperand(MCOperand::CreateImm(ARM_AM::rotr32(Imm, 2*Rot))); + ++OpIdx; + } + + return true; +} + +static bool DisassembleDPSoRegFrm(MCInst &MI, unsigned Opcode, uint32_t insn, + unsigned short NumOps, unsigned &NumOpsAdded) { + + const TargetInstrDesc &TID = ARMInsts[Opcode]; + unsigned short NumDefs = TID.getNumDefs(); + bool isUnary = isUnaryDP(TID.TSFlags); + const TargetOperandInfo *OpInfo = TID.OpInfo; + unsigned &OpIdx = NumOpsAdded; + + OpIdx = 0; + + // Disassemble register def if there is one. + if (NumDefs && (OpInfo[OpIdx].RegClass == ARM::GPRRegClassID)) { + MI.addOperand(MCOperand::CreateReg(getRegisterEnum(ARM::GPRRegClassID, + decodeRd(insn)))); + ++OpIdx; + } + + // Disassemble the src operands. + if (OpIdx >= NumOps) + return false; + + // BinaryDP has an Rn operand. + if (!isUnary) { + assert(OpInfo[OpIdx].RegClass == ARM::GPRRegClassID); + MI.addOperand(MCOperand::CreateReg(getRegisterEnum(ARM::GPRRegClassID, + decodeRn(insn)))); + ++OpIdx; + } + + // If this is a two-address operand, skip it, e.g., MOVCCs operand 1. + if (isUnary && (TID.getOperandConstraint(OpIdx, TOI::TIED_TO) != -1)) { + MI.addOperand(MCOperand::CreateReg(0)); + ++OpIdx; + } + + // Disassemble operand 2, which consists of three components. + if (OpIdx + 2 >= NumOps) + return false; + + assert((OpInfo[OpIdx].RegClass == ARM::GPRRegClassID) && + (OpInfo[OpIdx+1].RegClass == ARM::GPRRegClassID) && + (OpInfo[OpIdx+2].RegClass == 0)); + + // Register-controlled shifts have Inst{7} = 0 and Inst{4} = 1. + unsigned Rs = slice(insn, 4, 4); + + MI.addOperand(MCOperand::CreateReg(getRegisterEnum(ARM::GPRRegClassID, + decodeRm(insn)))); + if (Rs) { + // Register-controlled shifts: [Rm, Rs, shift]. + MI.addOperand(MCOperand::CreateReg(getRegisterEnum(ARM::GPRRegClassID, + decodeRs(insn)))); + // Inst{6-5} encodes the shift opcode. + ARM_AM::ShiftOpc ShOp = getShiftOpcForBits(slice(insn, 6, 5)); + MI.addOperand(MCOperand::CreateImm(ARM_AM::getSORegOpc(ShOp, 0))); + } else { + // Constant shifts: [Rm, reg0, shift_imm]. + MI.addOperand(MCOperand::CreateReg(0)); // NoRegister + // Inst{6-5} encodes the shift opcode. + ARM_AM::ShiftOpc ShOp = getShiftOpcForBits(slice(insn, 6, 5)); + // Inst{11-7} encodes the imm5 shift amount. + unsigned ShImm = slice(insn, 11, 7); + + // A8.4.1. Possible rrx or shift amount of 32... + getImmShiftSE(ShOp, ShImm); + MI.addOperand(MCOperand::CreateImm(ARM_AM::getSORegOpc(ShOp, ShImm))); + } + OpIdx += 3; + + return true; +} + +static bool DisassembleLdStFrm(MCInst &MI, unsigned Opcode, uint32_t insn, + unsigned short NumOps, unsigned &NumOpsAdded, bool isStore) { + + const TargetInstrDesc &TID = ARMInsts[Opcode]; + unsigned short NumDefs = TID.getNumDefs(); + bool isPrePost = isPrePostLdSt(TID.TSFlags); + const TargetOperandInfo *OpInfo = TID.OpInfo; + unsigned &OpIdx = NumOpsAdded; + + OpIdx = 0; + + assert((!isStore && NumDefs > 0) || (isStore && (NumDefs == 0 || isPrePost))); + + // Operand 0 of a pre- and post-indexed store is the address base writeback. + if (isPrePost && isStore) { + assert(OpInfo[OpIdx].RegClass == ARM::GPRRegClassID); + MI.addOperand(MCOperand::CreateReg(getRegisterEnum(ARM::GPRRegClassID, + decodeRn(insn)))); + ++OpIdx; + } + + // Disassemble the dst/src operand. + if (OpIdx >= NumOps) + return false; + + assert(OpInfo[OpIdx].RegClass == ARM::GPRRegClassID); + MI.addOperand(MCOperand::CreateReg(getRegisterEnum(ARM::GPRRegClassID, + decodeRd(insn)))); + ++OpIdx; + + // After dst of a pre- and post-indexed load is the address base writeback. + if (isPrePost && !isStore) { + assert(OpInfo[OpIdx].RegClass == ARM::GPRRegClassID); + MI.addOperand(MCOperand::CreateReg(getRegisterEnum(ARM::GPRRegClassID, + decodeRn(insn)))); + ++OpIdx; + } + + // Disassemble the base operand. + if (OpIdx >= NumOps) + return false; + + assert(OpInfo[OpIdx].RegClass == ARM::GPRRegClassID); + assert(!isPrePost || (TID.getOperandConstraint(OpIdx, TOI::TIED_TO) != -1)); + MI.addOperand(MCOperand::CreateReg(getRegisterEnum(ARM::GPRRegClassID, + decodeRn(insn)))); + ++OpIdx; + + // For reg/reg form, base reg is followed by +/- reg shop imm. + // For immediate form, it is followed by +/- imm12. + // See also ARMAddressingModes.h (Addressing Mode #2). + if (OpIdx + 1 >= NumOps) + return false; + + assert((OpInfo[OpIdx].RegClass == ARM::GPRRegClassID) && + (OpInfo[OpIdx+1].RegClass == 0)); + + ARM_AM::AddrOpc AddrOpcode = getUBit(insn) ? ARM_AM::add : ARM_AM::sub; + if (getIBit(insn) == 0) { + MI.addOperand(MCOperand::CreateReg(0)); + + // Disassemble the 12-bit immediate offset. + unsigned Imm12 = slice(insn, 11, 0); + unsigned Offset = ARM_AM::getAM2Opc(AddrOpcode, Imm12, ARM_AM::no_shift); + MI.addOperand(MCOperand::CreateImm(Offset)); + } else { + // Disassemble the offset reg (Rm), shift type, and immediate shift length. + MI.addOperand(MCOperand::CreateReg(getRegisterEnum(ARM::GPRRegClassID, + decodeRm(insn)))); + // Inst{6-5} encodes the shift opcode. + ARM_AM::ShiftOpc ShOp = getShiftOpcForBits(slice(insn, 6, 5)); + // Inst{11-7} encodes the imm5 shift amount. + unsigned ShImm = slice(insn, 11, 7); + + // A8.4.1. Possible rrx or shift amount of 32... + getImmShiftSE(ShOp, ShImm); + MI.addOperand(MCOperand::CreateImm( + ARM_AM::getAM2Opc(AddrOpcode, ShImm, ShOp))); + } + OpIdx += 2; + + return true; +} + +static bool DisassembleLdFrm(MCInst &MI, unsigned Opcode, uint32_t insn, + unsigned short NumOps, unsigned &NumOpsAdded) { + return DisassembleLdStFrm(MI, Opcode, insn, NumOps, NumOpsAdded, false); +} + +static bool DisassembleStFrm(MCInst &MI, unsigned Opcode, uint32_t insn, + unsigned short NumOps, unsigned &NumOpsAdded) { + return DisassembleLdStFrm(MI, Opcode, insn, NumOps, NumOpsAdded, true); +} + +static bool HasDualReg(unsigned Opcode) { + switch (Opcode) { + default: + return false; + case ARM::LDRD: case ARM::LDRD_PRE: case ARM::LDRD_POST: + case ARM::STRD: case ARM::STRD_PRE: case ARM::STRD_POST: + return true; + } +} + +static bool DisassembleLdStMiscFrm(MCInst &MI, unsigned Opcode, uint32_t insn, + unsigned short NumOps, unsigned &NumOpsAdded, bool isStore) { + + const TargetInstrDesc &TID = ARMInsts[Opcode]; + unsigned short NumDefs = TID.getNumDefs(); + bool isPrePost = isPrePostLdSt(TID.TSFlags); + const TargetOperandInfo *OpInfo = TID.OpInfo; + unsigned &OpIdx = NumOpsAdded; + + OpIdx = 0; + + assert((!isStore && NumDefs > 0) || (isStore && (NumDefs == 0 || isPrePost))); + + // Operand 0 of a pre- and post-indexed store is the address base writeback. + if (isPrePost && isStore) { + assert(OpInfo[OpIdx].RegClass == ARM::GPRRegClassID); + MI.addOperand(MCOperand::CreateReg(getRegisterEnum(ARM::GPRRegClassID, + decodeRn(insn)))); + ++OpIdx; + } + + bool DualReg = HasDualReg(Opcode); + + // Disassemble the dst/src operand. + if (OpIdx >= NumOps) + return false; + + assert(OpInfo[OpIdx].RegClass == ARM::GPRRegClassID); + MI.addOperand(MCOperand::CreateReg(getRegisterEnum(ARM::GPRRegClassID, + decodeRd(insn)))); + ++OpIdx; + + // Fill in LDRD and STRD's second operand. + if (DualReg) { + MI.addOperand(MCOperand::CreateReg(getRegisterEnum(ARM::GPRRegClassID, + decodeRd(insn) + 1))); + ++OpIdx; + } + + // After dst of a pre- and post-indexed load is the address base writeback. + if (isPrePost && !isStore) { + assert(OpInfo[OpIdx].RegClass == ARM::GPRRegClassID); + MI.addOperand(MCOperand::CreateReg(getRegisterEnum(ARM::GPRRegClassID, + decodeRn(insn)))); + ++OpIdx; + } + + // Disassemble the base operand. + if (OpIdx >= NumOps) + return false; + + assert(OpInfo[OpIdx].RegClass == ARM::GPRRegClassID); + assert(!isPrePost || (TID.getOperandConstraint(OpIdx, TOI::TIED_TO) != -1)); + MI.addOperand(MCOperand::CreateReg(getRegisterEnum(ARM::GPRRegClassID, + decodeRn(insn)))); + ++OpIdx; + + // For reg/reg form, base reg is followed by +/- reg. + // For immediate form, it is followed by +/- imm8. + // See also ARMAddressingModes.h (Addressing Mode #3). + if (OpIdx + 1 >= NumOps) + return false; + + assert((OpInfo[OpIdx].RegClass == ARM::GPRRegClassID) && + (OpInfo[OpIdx+1].RegClass == 0)); + + ARM_AM::AddrOpc AddrOpcode = getUBit(insn) ? ARM_AM::add : ARM_AM::sub; + if (getAM3IBit(insn) == 1) { + MI.addOperand(MCOperand::CreateReg(0)); + + // Disassemble the 8-bit immediate offset. + unsigned Imm4H = (insn >> ARMII::ImmHiShift) & 0xF; + unsigned Imm4L = insn & 0xF; + unsigned Offset = ARM_AM::getAM3Opc(AddrOpcode, (Imm4H << 4) | Imm4L); + MI.addOperand(MCOperand::CreateImm(Offset)); + } else { + // Disassemble the offset reg (Rm). + MI.addOperand(MCOperand::CreateReg(getRegisterEnum(ARM::GPRRegClassID, + decodeRm(insn)))); + unsigned Offset = ARM_AM::getAM3Opc(AddrOpcode, 0); + MI.addOperand(MCOperand::CreateImm(Offset)); + } + OpIdx += 2; + + return true; +} + +static bool DisassembleLdMiscFrm(MCInst &MI, unsigned Opcode, uint32_t insn, + unsigned short NumOps, unsigned &NumOpsAdded) { + return DisassembleLdStMiscFrm(MI, Opcode, insn, NumOps, NumOpsAdded, false); +} + +static bool DisassembleStMiscFrm(MCInst &MI, unsigned Opcode, uint32_t insn, + unsigned short NumOps, unsigned &NumOpsAdded) { + return DisassembleLdStMiscFrm(MI, Opcode, insn, NumOps, NumOpsAdded, true); +} + +// The algorithm for disassembly of LdStMulFrm is different from others because +// it explicitly populates the two predicate operands after operand 0 (the base) +// and operand 1 (the AM4 mode imm). After operand 3, we need to populate the +// reglist with each affected register encoded as an MCOperand. +static bool DisassembleLdStMulFrm(MCInst &MI, unsigned Opcode, uint32_t insn, + unsigned short NumOps, unsigned &NumOpsAdded) { + + assert(NumOps == 5 && "LdStMulFrm expects NumOps of 5"); + + unsigned &OpIdx = NumOpsAdded; + + unsigned Base = getRegisterEnum(ARM::GPRRegClassID, decodeRn(insn)); + MI.addOperand(MCOperand::CreateReg(Base)); + + ARM_AM::AMSubMode SubMode = getAMSubModeForBits(getPUBits(insn)); + bool WB = getWBit(insn) == 1; + MI.addOperand(MCOperand::CreateImm(ARM_AM::getAM4ModeImm(SubMode, WB))); + + // Handling the two predicate operands before the reglist. + int64_t CondVal = insn >> ARMII::CondShift; + MI.addOperand(MCOperand::CreateImm(CondVal == 0xF ? 0xE : CondVal)); + MI.addOperand(MCOperand::CreateReg(ARM::CPSR)); + + OpIdx = 4; + + // Fill the variadic part of reglist. + unsigned RegListBits = insn & ((1 << 16) - 1); + for (unsigned i = 0; i < 16; ++i) { + if ((RegListBits >> i) & 1) { + MI.addOperand(MCOperand::CreateReg(getRegisterEnum(ARM::GPRRegClassID, + i))); + ++OpIdx; + } + } + + return true; +} + +// LDREX, LDREXB, LDREXH: Rd Rn +// LDREXD: Rd Rd+1 Rn +// STREX, STREXB, STREXH: Rd Rm Rn +// STREXD: Rd Rm Rm+1 Rn +// +// SWP, SWPB: Rd Rm Rn +static bool DisassembleLdStExFrm(MCInst &MI, unsigned Opcode, uint32_t insn, + unsigned short NumOps, unsigned &NumOpsAdded) { + + const TargetOperandInfo *OpInfo = ARMInsts[Opcode].OpInfo; + unsigned &OpIdx = NumOpsAdded; + + OpIdx = 0; + + assert(NumOps >= 2 + && OpInfo[0].RegClass == ARM::GPRRegClassID + && OpInfo[1].RegClass == ARM::GPRRegClassID); + + bool isStore = slice(insn, 20, 20) == 0; + bool isDW = (Opcode == ARM::LDREXD || Opcode == ARM::STREXD); + + // Add the destination operand. + MI.addOperand(MCOperand::CreateReg(getRegisterEnum(ARM::GPRRegClassID, + decodeRd(insn)))); + ++OpIdx; + + // Store register Exclusive needs a source operand. + if (isStore) { + MI.addOperand(MCOperand::CreateReg(getRegisterEnum(ARM::GPRRegClassID, + decodeRm(insn)))); + ++OpIdx; + + if (isDW) { + MI.addOperand(MCOperand::CreateReg(getRegisterEnum(ARM::GPRRegClassID, + decodeRm(insn)+1))); + ++OpIdx; + } + } else if (isDW) { + MI.addOperand(MCOperand::CreateReg(getRegisterEnum(ARM::GPRRegClassID, + decodeRd(insn)+1))); + ++OpIdx; + } + + // Finally add the pointer operand. + MI.addOperand(MCOperand::CreateReg(getRegisterEnum(ARM::GPRRegClassID, + decodeRn(insn)))); + ++OpIdx; + + return true; +} + +// Misc. Arithmetic Instructions. +// CLZ: Rd Rm +// PKHBT, PKHTB: Rd Rn Rm , LSL/ASR #imm5 +// RBIT, REV, REV16, REVSH: Rd Rm +static bool DisassembleArithMiscFrm(MCInst &MI, unsigned Opcode, uint32_t insn, + unsigned short NumOps, unsigned &NumOpsAdded) { + + const TargetOperandInfo *OpInfo = ARMInsts[Opcode].OpInfo; + unsigned &OpIdx = NumOpsAdded; + + OpIdx = 0; + + assert(NumOps >= 2 + && OpInfo[0].RegClass == ARM::GPRRegClassID + && OpInfo[1].RegClass == ARM::GPRRegClassID); + + bool ThreeReg = NumOps > 2 && OpInfo[2].RegClass == ARM::GPRRegClassID; + + MI.addOperand(MCOperand::CreateReg(getRegisterEnum(ARM::GPRRegClassID, + decodeRd(insn)))); + ++OpIdx; + + if (ThreeReg) { + assert(NumOps >= 4); + MI.addOperand(MCOperand::CreateReg(getRegisterEnum(ARM::GPRRegClassID, + decodeRn(insn)))); + ++OpIdx; + } + + MI.addOperand(MCOperand::CreateReg(getRegisterEnum(ARM::GPRRegClassID, + decodeRm(insn)))); + ++OpIdx; + + // If there is still an operand info left which is an immediate operand, add + // an additional imm5 LSL/ASR operand. + if (ThreeReg && OpInfo[OpIdx].RegClass == 0 + && !OpInfo[OpIdx].isPredicate() && !OpInfo[OpIdx].isOptionalDef()) { + // Extract the 5-bit immediate field Inst{11-7}. + unsigned ShiftAmt = (insn >> ARMII::ShiftShift) & 0x1F; + MI.addOperand(MCOperand::CreateImm(ShiftAmt)); + ++OpIdx; + } + + return true; +} + +// Extend instructions. +// SXT* and UXT*: Rd [Rn] Rm [rot_imm]. +// The 2nd operand register is Rn and the 3rd operand regsiter is Rm for the +// three register operand form. Otherwise, Rn=0b1111 and only Rm is used. +static bool DisassembleExtFrm(MCInst &MI, unsigned Opcode, uint32_t insn, + unsigned short NumOps, unsigned &NumOpsAdded) { + + const TargetOperandInfo *OpInfo = ARMInsts[Opcode].OpInfo; + unsigned &OpIdx = NumOpsAdded; + + OpIdx = 0; + + assert(NumOps >= 2 + && OpInfo[0].RegClass == ARM::GPRRegClassID + && OpInfo[1].RegClass == ARM::GPRRegClassID); + + bool ThreeReg = NumOps > 2 && OpInfo[2].RegClass == ARM::GPRRegClassID; + + MI.addOperand(MCOperand::CreateReg(getRegisterEnum(ARM::GPRRegClassID, + decodeRd(insn)))); + ++OpIdx; + + if (ThreeReg) { + MI.addOperand(MCOperand::CreateReg(getRegisterEnum(ARM::GPRRegClassID, + decodeRn(insn)))); + ++OpIdx; + } + + MI.addOperand(MCOperand::CreateReg(getRegisterEnum(ARM::GPRRegClassID, + decodeRm(insn)))); + ++OpIdx; + + // If there is still an operand info left which is an immediate operand, add + // an additional rotate immediate operand. + if (OpIdx < NumOps && OpInfo[OpIdx].RegClass == 0 + && !OpInfo[OpIdx].isPredicate() && !OpInfo[OpIdx].isOptionalDef()) { + // Extract the 2-bit rotate field Inst{11-10}. + unsigned rot = (insn >> ARMII::ExtRotImmShift) & 3; + // Rotation by 8, 16, or 24 bits. + MI.addOperand(MCOperand::CreateImm(rot << 3)); + ++OpIdx; + } + + return true; +} + +///////////////////////////////////// +// // +// Utility Functions For VFP // +// // +///////////////////////////////////// + +// Extract/Decode Dd/Sd: +// +// SP => d = UInt(Vd:D) +// DP => d = UInt(D:Vd) +static unsigned decodeVFPRd(uint32_t insn, bool isSPVFP) { + return isSPVFP ? (decodeRd(insn) << 1 | getDBit(insn)) + : (decodeRd(insn) | getDBit(insn) << 4); +} + +// Extract/Decode Dn/Sn: +// +// SP => n = UInt(Vn:N) +// DP => n = UInt(N:Vn) +static unsigned decodeVFPRn(uint32_t insn, bool isSPVFP) { + return isSPVFP ? (decodeRn(insn) << 1 | getNBit(insn)) + : (decodeRn(insn) | getNBit(insn) << 4); +} + +// Extract/Decode Dm/Sm: +// +// SP => m = UInt(Vm:M) +// DP => m = UInt(M:Vm) +static unsigned decodeVFPRm(uint32_t insn, bool isSPVFP) { + return isSPVFP ? (decodeRm(insn) << 1 | getMBit(insn)) + : (decodeRm(insn) | getMBit(insn) << 4); +} + +// A7.5.1 +#if 0 +static uint64_t VFPExpandImm(unsigned char byte, unsigned N) { + assert(N == 32 || N == 64); + + uint64_t Result; + unsigned bit6 = slice(byte, 6, 6); + if (N == 32) { + Result = slice(byte, 7, 7) << 31 | slice(byte, 5, 0) << 19; + if (bit6) + Result |= 0x1f << 25; + else + Result |= 0x1 << 30; + } else { + Result = (uint64_t)slice(byte, 7, 7) << 63 | + (uint64_t)slice(byte, 5, 0) << 48; + if (bit6) + Result |= 0xffL << 54; + else + Result |= 0x1L << 62; + } + return Result; +} +#endif + +// VFP Unary Format Instructions: +// +// VCMP[E]ZD, VCMP[E]ZS: compares one floating-point register with zero +// VCVTDS, VCVTSD: converts between double-precision and single-precision +// The rest of the instructions have homogeneous [VFP]Rd and [VFP]Rm registers. +static bool DisassembleVFPUnaryFrm(MCInst &MI, unsigned Opcode, uint32_t insn, + unsigned short NumOps, unsigned &NumOpsAdded) { + + assert(NumOps >= 1 && "VFPUnaryFrm expects NumOps >= 1"); + + const TargetOperandInfo *OpInfo = ARMInsts[Opcode].OpInfo; + unsigned &OpIdx = NumOpsAdded; + + OpIdx = 0; + + unsigned RegClass = OpInfo[OpIdx].RegClass; + assert(RegClass == ARM::SPRRegClassID || RegClass == ARM::DPRRegClassID); + bool isSP = (RegClass == ARM::SPRRegClassID); + + MI.addOperand(MCOperand::CreateReg( + getRegisterEnum(RegClass, decodeVFPRd(insn, isSP)))); + ++OpIdx; + + // Early return for compare with zero instructions. + if (Opcode == ARM::VCMPEZD || Opcode == ARM::VCMPEZS + || Opcode == ARM::VCMPZD || Opcode == ARM::VCMPZS) + return true; + + RegClass = OpInfo[OpIdx].RegClass; + assert(RegClass == ARM::SPRRegClassID || RegClass == ARM::DPRRegClassID); + isSP = (RegClass == ARM::SPRRegClassID); + + MI.addOperand(MCOperand::CreateReg( + getRegisterEnum(RegClass, decodeVFPRm(insn, isSP)))); + ++OpIdx; + + return true; +} + +// All the instructions have homogeneous [VFP]Rd, [VFP]Rn, and [VFP]Rm regs. +// Some of them have operand constraints which tie the first operand in the +// InOperandList to that of the dst. As far as asm printing is concerned, this +// tied_to operand is simply skipped. +static bool DisassembleVFPBinaryFrm(MCInst &MI, unsigned Opcode, uint32_t insn, + unsigned short NumOps, unsigned &NumOpsAdded) { + + assert(NumOps >= 3 && "VFPBinaryFrm expects NumOps >= 3"); + + const TargetInstrDesc &TID = ARMInsts[Opcode]; + const TargetOperandInfo *OpInfo = TID.OpInfo; + unsigned &OpIdx = NumOpsAdded; + + OpIdx = 0; + + unsigned RegClass = OpInfo[OpIdx].RegClass; + assert(RegClass == ARM::SPRRegClassID || RegClass == ARM::DPRRegClassID); + bool isSP = (RegClass == ARM::SPRRegClassID); + + MI.addOperand(MCOperand::CreateReg( + getRegisterEnum(RegClass, decodeVFPRd(insn, isSP)))); + ++OpIdx; + + // Skip tied_to operand constraint. + if (TID.getOperandConstraint(OpIdx, TOI::TIED_TO) != -1) { + assert(NumOps >= 4); + MI.addOperand(MCOperand::CreateReg(0)); + ++OpIdx; + } + + MI.addOperand(MCOperand::CreateReg( + getRegisterEnum(RegClass, decodeVFPRn(insn, isSP)))); + ++OpIdx; + + MI.addOperand(MCOperand::CreateReg( + getRegisterEnum(RegClass, decodeVFPRm(insn, isSP)))); + ++OpIdx; + + return true; +} + +// A8.6.295 vcvt (floating-point <-> integer) +// Int to FP: VSITOD, VSITOS, VUITOD, VUITOS +// FP to Int: VTOSI[Z|R]D, VTOSI[Z|R]S, VTOUI[Z|R]D, VTOUI[Z|R]S +// +// A8.6.297 vcvt (floating-point and fixed-point) +// Dd|Sd Dd|Sd(TIED_TO) #fbits(= 16|32 - UInt(imm4:i)) +static bool DisassembleVFPConv1Frm(MCInst &MI, unsigned Opcode, uint32_t insn, + unsigned short NumOps, unsigned &NumOpsAdded) { + + assert(NumOps >= 2 && "VFPConv1Frm expects NumOps >= 2"); + + const TargetInstrDesc &TID = ARMInsts[Opcode]; + const TargetOperandInfo *OpInfo = TID.OpInfo; + + bool SP = slice(insn, 8, 8) == 0; // A8.6.295 & A8.6.297 + bool fixed_point = slice(insn, 17, 17) == 1; // A8.6.297 + unsigned RegClassID = SP ? ARM::SPRRegClassID : ARM::DPRRegClassID; + + if (fixed_point) { + // A8.6.297 + assert(NumOps >= 3); + int size = slice(insn, 7, 7) == 0 ? 16 : 32; + int fbits = size - (slice(insn,3,0) << 1 | slice(insn,5,5)); + MI.addOperand(MCOperand::CreateReg( + getRegisterEnum(RegClassID, + decodeVFPRd(insn, SP)))); + + assert(TID.getOperandConstraint(1, TOI::TIED_TO) != -1); + MI.addOperand(MI.getOperand(0)); + + assert(OpInfo[2].RegClass == 0 && !OpInfo[2].isPredicate() && + !OpInfo[2].isOptionalDef()); + MI.addOperand(MCOperand::CreateImm(fbits)); + + NumOpsAdded = 3; + } else { + // A8.6.295 + // The Rd (destination) and Rm (source) bits have different interpretations + // depending on their single-precisonness. + unsigned d, m; + if (slice(insn, 18, 18) == 1) { // to_integer operation + d = decodeVFPRd(insn, true /* Is Single Precision */); + MI.addOperand(MCOperand::CreateReg( + getRegisterEnum(ARM::SPRRegClassID, d))); + m = decodeVFPRm(insn, SP); + MI.addOperand(MCOperand::CreateReg(getRegisterEnum(RegClassID, m))); + } else { + d = decodeVFPRd(insn, SP); + MI.addOperand(MCOperand::CreateReg(getRegisterEnum(RegClassID, d))); + m = decodeVFPRm(insn, true /* Is Single Precision */); + MI.addOperand(MCOperand::CreateReg( + getRegisterEnum(ARM::SPRRegClassID, m))); + } + NumOpsAdded = 2; + } + + return true; +} + +// VMOVRS - A8.6.330 +// Rt => Rd; Sn => UInt(Vn:N) +static bool DisassembleVFPConv2Frm(MCInst &MI, unsigned Opcode, uint32_t insn, + unsigned short NumOps, unsigned &NumOpsAdded) { + + assert(NumOps >= 2 && "VFPConv2Frm expects NumOps >= 2"); + + MI.addOperand(MCOperand::CreateReg(getRegisterEnum(ARM::GPRRegClassID, + decodeRd(insn)))); + MI.addOperand(MCOperand::CreateReg(getRegisterEnum(ARM::SPRRegClassID, + decodeVFPRn(insn, true)))); + NumOpsAdded = 2; + return true; +} + +// VMOVRRD - A8.6.332 +// Rt => Rd; Rt2 => Rn; Dm => UInt(M:Vm) +// +// VMOVRRS - A8.6.331 +// Rt => Rd; Rt2 => Rn; Sm => UInt(Vm:M); Sm1 = Sm+1 +static bool DisassembleVFPConv3Frm(MCInst &MI, unsigned Opcode, uint32_t insn, + unsigned short NumOps, unsigned &NumOpsAdded) { + + assert(NumOps >= 3 && "VFPConv3Frm expects NumOps >= 3"); + + const TargetOperandInfo *OpInfo = ARMInsts[Opcode].OpInfo; + unsigned &OpIdx = NumOpsAdded; + + MI.addOperand(MCOperand::CreateReg(getRegisterEnum(ARM::GPRRegClassID, + decodeRd(insn)))); + MI.addOperand(MCOperand::CreateReg(getRegisterEnum(ARM::GPRRegClassID, + decodeRn(insn)))); + OpIdx = 2; + + if (OpInfo[OpIdx].RegClass == ARM::SPRRegClassID) { + unsigned Sm = decodeVFPRm(insn, true); + MI.addOperand(MCOperand::CreateReg(getRegisterEnum(ARM::SPRRegClassID, + Sm))); + MI.addOperand(MCOperand::CreateReg(getRegisterEnum(ARM::SPRRegClassID, + Sm+1))); + OpIdx += 2; + } else { + MI.addOperand(MCOperand::CreateReg( + getRegisterEnum(ARM::DPRRegClassID, + decodeVFPRm(insn, false)))); + ++OpIdx; + } + return true; +} + +// VMOVSR - A8.6.330 +// Rt => Rd; Sn => UInt(Vn:N) +static bool DisassembleVFPConv4Frm(MCInst &MI, unsigned Opcode, uint32_t insn, + unsigned short NumOps, unsigned &NumOpsAdded) { + + assert(NumOps >= 2 && "VFPConv4Frm expects NumOps >= 2"); + + MI.addOperand(MCOperand::CreateReg(getRegisterEnum(ARM::SPRRegClassID, + decodeVFPRn(insn, true)))); + MI.addOperand(MCOperand::CreateReg(getRegisterEnum(ARM::GPRRegClassID, + decodeRd(insn)))); + NumOpsAdded = 2; + return true; +} + +// VMOVDRR - A8.6.332 +// Rt => Rd; Rt2 => Rn; Dm => UInt(M:Vm) +// +// VMOVRRS - A8.6.331 +// Rt => Rd; Rt2 => Rn; Sm => UInt(Vm:M); Sm1 = Sm+1 +static bool DisassembleVFPConv5Frm(MCInst &MI, unsigned Opcode, uint32_t insn, + unsigned short NumOps, unsigned &NumOpsAdded) { + + assert(NumOps >= 3 && "VFPConv5Frm expects NumOps >= 3"); + + const TargetOperandInfo *OpInfo = ARMInsts[Opcode].OpInfo; + unsigned &OpIdx = NumOpsAdded; + + OpIdx = 0; + + if (OpInfo[OpIdx].RegClass == ARM::SPRRegClassID) { + unsigned Sm = decodeVFPRm(insn, true); + MI.addOperand(MCOperand::CreateReg(getRegisterEnum(ARM::SPRRegClassID, + Sm))); + MI.addOperand(MCOperand::CreateReg(getRegisterEnum(ARM::SPRRegClassID, + Sm+1))); + OpIdx += 2; + } else { + MI.addOperand(MCOperand::CreateReg( + getRegisterEnum(ARM::DPRRegClassID, + decodeVFPRm(insn, false)))); + ++OpIdx; + } + + MI.addOperand(MCOperand::CreateReg(getRegisterEnum(ARM::GPRRegClassID, + decodeRd(insn)))); + MI.addOperand(MCOperand::CreateReg(getRegisterEnum(ARM::GPRRegClassID, + decodeRn(insn)))); + OpIdx += 2; + return true; +} + +// VFP Load/Store Instructions. +// VLDRD, VLDRS, VSTRD, VSTRS +static bool DisassembleVFPLdStFrm(MCInst &MI, unsigned Opcode, uint32_t insn, + unsigned short NumOps, unsigned &NumOpsAdded) { + + assert(NumOps >= 3 && "VFPLdStFrm expects NumOps >= 3"); + + bool isSPVFP = (Opcode == ARM::VLDRS || Opcode == ARM::VSTRS) ? true : false; + unsigned RegClassID = isSPVFP ? ARM::SPRRegClassID : ARM::DPRRegClassID; + + // Extract Dd/Sd for operand 0. + unsigned RegD = decodeVFPRd(insn, isSPVFP); + + MI.addOperand(MCOperand::CreateReg(getRegisterEnum(RegClassID, RegD))); + + unsigned Base = getRegisterEnum(ARM::GPRRegClassID, decodeRn(insn)); + MI.addOperand(MCOperand::CreateReg(Base)); + + // Next comes the AM5 Opcode. + ARM_AM::AddrOpc AddrOpcode = getUBit(insn) ? ARM_AM::add : ARM_AM::sub; + unsigned char Imm8 = insn & 0xFF; + MI.addOperand(MCOperand::CreateImm(ARM_AM::getAM5Opc(AddrOpcode, Imm8))); + + NumOpsAdded = 3; + + return true; +} + +// VFP Load/Store Multiple Instructions. +// This is similar to the algorithm for LDM/STM in that operand 0 (the base) and +// operand 1 (the AM5 mode imm) is followed by two predicate operands. It is +// followed by a reglist of either DPR(s) or SPR(s). +// +// VLDMD, VLDMS, VSTMD, VSTMS +static bool DisassembleVFPLdStMulFrm(MCInst &MI, unsigned Opcode, uint32_t insn, + unsigned short NumOps, unsigned &NumOpsAdded) { + + assert(NumOps == 5 && "VFPLdStMulFrm expects NumOps of 5"); + + unsigned &OpIdx = NumOpsAdded; + + unsigned Base = getRegisterEnum(ARM::GPRRegClassID, decodeRn(insn)); + MI.addOperand(MCOperand::CreateReg(Base)); + + // Next comes the AM5 Opcode. + ARM_AM::AMSubMode SubMode = getAMSubModeForBits(getPUBits(insn)); + bool WB = getWBit(insn) == 1; + unsigned char Imm8 = insn & 0xFF; + MI.addOperand(MCOperand::CreateImm(ARM_AM::getAM5Opc(SubMode, WB, Imm8))); + + // Handling the two predicate operands before the reglist. + int64_t CondVal = insn >> ARMII::CondShift; + MI.addOperand(MCOperand::CreateImm(CondVal == 0xF ? 0xE : CondVal)); + MI.addOperand(MCOperand::CreateReg(ARM::CPSR)); + + OpIdx = 4; + + bool isSPVFP = (Opcode == ARM::VLDMS || Opcode == ARM::VSTMS) ? true : false; + unsigned RegClassID = isSPVFP ? ARM::SPRRegClassID : ARM::DPRRegClassID; + + // Extract Dd/Sd. + unsigned RegD = decodeVFPRd(insn, isSPVFP); + + // Fill the variadic part of reglist. + unsigned Regs = isSPVFP ? Imm8 : Imm8/2; + for (unsigned i = 0; i < Regs; ++i) { + MI.addOperand(MCOperand::CreateReg(getRegisterEnum(RegClassID, + RegD + i))); + ++OpIdx; + } + + return true; +} + +// Misc. VFP Instructions. +// FMSTAT (vmrs with Rt=0b1111, i.e., to apsr_nzcv and no register operand) +// FCONSTD (DPR and a VFPf64Imm operand) +// FCONSTS (SPR and a VFPf32Imm operand) +// VMRS/VMSR (GPR operand) +static bool DisassembleVFPMiscFrm(MCInst &MI, unsigned Opcode, uint32_t insn, + unsigned short NumOps, unsigned &NumOpsAdded) { + + const TargetOperandInfo *OpInfo = ARMInsts[Opcode].OpInfo; + unsigned &OpIdx = NumOpsAdded; + + OpIdx = 0; + + if (Opcode == ARM::FMSTAT) + return true; + + assert(NumOps >= 2); + + unsigned RegEnum = 0; + switch (OpInfo[0].RegClass) { + case ARM::DPRRegClassID: + RegEnum = getRegisterEnum(ARM::DPRRegClassID, decodeVFPRd(insn, false)); + break; + case ARM::SPRRegClassID: + RegEnum = getRegisterEnum(ARM::SPRRegClassID, decodeVFPRd(insn, true)); + break; + case ARM::GPRRegClassID: + RegEnum = getRegisterEnum(ARM::GPRRegClassID, decodeRd(insn)); + break; + default: + llvm_unreachable("Invalid reg class id"); + } + + MI.addOperand(MCOperand::CreateReg(RegEnum)); + ++OpIdx; + + // Extract/decode the f64/f32 immediate. + if (OpIdx < NumOps && OpInfo[OpIdx].RegClass == 0 + && !OpInfo[OpIdx].isPredicate() && !OpInfo[OpIdx].isOptionalDef()) { + // The asm syntax specifies the before-expanded . + // Not VFPExpandImm(slice(insn,19,16) << 4 | slice(insn, 3, 0), + // Opcode == ARM::FCONSTD ? 64 : 32) + MI.addOperand(MCOperand::CreateImm(slice(insn,19,16)<<4 | slice(insn,3,0))); + ++OpIdx; + } + + return true; +} + +// DisassembleThumbFrm() is defined in ThumbDisassemblerCore.cpp.inc file. +#include "ThumbDisassemblerCore.cpp.inc" + +///////////////////////////////////////////////////// +// // +// Utility Functions For ARM Advanced SIMD // +// // +///////////////////////////////////////////////////// + +// The following NEON namings are based on A8.6.266 VABA, VABAL. Notice that +// A8.6.303 VDUP (ARM core register)'s D/Vd pair is the N/Vn pair of VABA/VABAL. + +// A7.3 Register encoding + +// Extract/Decode NEON D/Vd: +// +// Note that for quadword, Qd = UInt(D:Vd<3:1>) = Inst{22:15-13}, whereas for +// doubleword, Dd = UInt(D:Vd). We compensate for this difference by +// handling it in the getRegisterEnum() utility function. +// D = Inst{22}, Vd = Inst{15-12} +static unsigned decodeNEONRd(uint32_t insn) { + return ((insn >> ARMII::NEON_D_BitShift) & 1) << 4 + | (insn >> ARMII::NEON_RegRdShift) & ARMII::NEONRegMask; +} + +// Extract/Decode NEON N/Vn: +// +// Note that for quadword, Qn = UInt(N:Vn<3:1>) = Inst{7:19-17}, whereas for +// doubleword, Dn = UInt(N:Vn). We compensate for this difference by +// handling it in the getRegisterEnum() utility function. +// N = Inst{7}, Vn = Inst{19-16} +static unsigned decodeNEONRn(uint32_t insn) { + return ((insn >> ARMII::NEON_N_BitShift) & 1) << 4 + | (insn >> ARMII::NEON_RegRnShift) & ARMII::NEONRegMask; +} + +// Extract/Decode NEON M/Vm: +// +// Note that for quadword, Qm = UInt(M:Vm<3:1>) = Inst{5:3-1}, whereas for +// doubleword, Dm = UInt(M:Vm). We compensate for this difference by +// handling it in the getRegisterEnum() utility function. +// M = Inst{5}, Vm = Inst{3-0} +static unsigned decodeNEONRm(uint32_t insn) { + return ((insn >> ARMII::NEON_M_BitShift) & 1) << 4 + | (insn >> ARMII::NEON_RegRmShift) & ARMII::NEONRegMask; +} + +namespace { +enum ElemSize { + ESizeNA = 0, + ESize8 = 8, + ESize16 = 16, + ESize32 = 32, + ESize64 = 64 +}; +} // End of unnamed namespace + +// size field -> Inst{11-10} +// index_align field -> Inst{7-4} +// +// The Lane Index interpretation depends on the Data Size: +// 8 (encoded as size = 0b00) -> Index = index_align[3:1] +// 16 (encoded as size = 0b01) -> Index = index_align[3:2] +// 32 (encoded as size = 0b10) -> Index = index_align[3] +// +// Ref: A8.6.317 VLD4 (single 4-element structure to one lane). +static unsigned decodeLaneIndex(uint32_t insn) { + unsigned size = insn >> 10 & 3; + assert(size == 0 || size == 1 || size == 2); + + unsigned index_align = insn >> 4 & 0xF; + return (index_align >> 1) >> size; +} + +// imm64 = AdvSIMDExpandImm(op, cmode, i:imm3:imm4) +// op = Inst{5}, cmode = Inst{11-8} +// i = Inst{24} (ARM architecture) +// imm3 = Inst{18-16}, imm4 = Inst{3-0} +// Ref: Table A7-15 Modified immediate values for Advanced SIMD instructions. +static uint64_t decodeN1VImm(uint32_t insn, ElemSize esize) { + unsigned char cmode = (insn >> 8) & 0xF; + unsigned char Imm8 = ((insn >> 24) & 1) << 7 | + ((insn >> 16) & 7) << 4 | + (insn & 0xF); + uint64_t Imm64 = 0; + + switch (esize) { + case ESize8: + Imm64 = Imm8; + break; + case ESize16: + Imm64 = Imm8 << 8*(cmode >> 1 & 1); + break; + case ESize32: { + if (cmode == 12) + Imm64 = (Imm8 << 8) | 0xFF; + else if (cmode == 13) + Imm64 = (Imm8 << 16) | 0xFFFF; + else { + // Imm8 to be shifted left by how many bytes... + Imm64 = Imm8 << 8*(cmode >> 1 & 3); + } + break; + } + case ESize64: { + for (unsigned i = 0; i < 8; ++i) + if ((Imm8 >> i) & 1) + Imm64 |= 0xFF << 8*i; + break; + } + default: + assert(0 && "Unreachable code!"); + return 0; + } + + return Imm64; +} + +// A8.6.339 VMUL, VMULL (by scalar) +// ESize16 => m = Inst{2-0} (Vm<2:0>) D0-D7 +// ESize32 => m = Inst{3-0} (Vm<3:0>) D0-D15 +static unsigned decodeRestrictedDm(uint32_t insn, ElemSize esize) { + switch (esize) { + case ESize16: + return insn & 7; + case ESize32: + return insn & 0xF; + default: + assert(0 && "Unreachable code!"); + return 0; + } +} + +// A8.6.339 VMUL, VMULL (by scalar) +// ESize16 => index = Inst{5:3} (M:Vm<3>) D0-D7 +// ESize32 => index = Inst{5} (M) D0-D15 +static unsigned decodeRestrictedDmIndex(uint32_t insn, ElemSize esize) { + switch (esize) { + case ESize16: + return (((insn >> 5) & 1) << 1) | ((insn >> 3) & 1); + case ESize32: + return (insn >> 5) & 1; + default: + assert(0 && "Unreachable code!"); + return 0; + } +} + +// A8.6.296 VCVT (between floating-point and fixed-point, Advanced SIMD) +// (64 - ) is encoded as imm6, i.e., Inst{21-16}. +static unsigned decodeVCVTFractionBits(uint32_t insn) { + return 64 - ((insn >> 16) & 0x3F); +} + +// A8.6.302 VDUP (scalar) +// ESize8 => index = Inst{19-17} +// ESize16 => index = Inst{19-18} +// ESize32 => index = Inst{19} +static unsigned decodeNVLaneDupIndex(uint32_t insn, ElemSize esize) { + switch (esize) { + case ESize8: + return (insn >> 17) & 7; + case ESize16: + return (insn >> 18) & 3; + case ESize32: + return (insn >> 19) & 1; + default: + assert(0 && "Unspecified element size!"); + return 0; + } +} + +// A8.6.328 VMOV (ARM core register to scalar) +// A8.6.329 VMOV (scalar to ARM core register) +// ESize8 => index = Inst{21:6-5} +// ESize16 => index = Inst{21:6} +// ESize32 => index = Inst{21} +static unsigned decodeNVLaneOpIndex(uint32_t insn, ElemSize esize) { + switch (esize) { + case ESize8: + return ((insn >> 21) & 1) << 2 | ((insn >> 5) & 3); + case ESize16: + return ((insn >> 21) & 1) << 1 | ((insn >> 6) & 1); + case ESize32: + return ((insn >> 21) & 1); + default: + assert(0 && "Unspecified element size!"); + return 0; + } +} + +// Imm6 = Inst{21-16}, L = Inst{7} +// +// NormalShift == true (A8.6.376 VRSHR, A8.6.368 VQSHRN): +// case L:imm6 of +// '0001xxx' => esize = 8; shift_amount = 16 - imm6 +// '001xxxx' => esize = 16; shift_amount = 32 - imm6 +// '01xxxxx' => esize = 32; shift_amount = 64 - imm6 +// '1xxxxxx' => esize = 64; shift_amount = 64 - imm6 +// +// NormalShift == false (A8.6.367 VQSHL, A8.6.387 VSLI): +// case L:imm6 of +// '0001xxx' => esize = 8; shift_amount = imm6 - 8 +// '001xxxx' => esize = 16; shift_amount = imm6 - 16 +// '01xxxxx' => esize = 32; shift_amount = imm6 - 32 +// '1xxxxxx' => esize = 64; shift_amount = imm6 +// +static unsigned decodeNVSAmt(uint32_t insn, bool NormalShift) { + ElemSize esize = ESizeNA; + unsigned L = (insn >> 7) & 1; + unsigned imm6 = (insn >> 16) & 0x3F; + if (L == 0) { + if (imm6 >> 3 == 1) + esize = ESize8; + else if (imm6 >> 4 == 1) + esize = ESize16; + else if (imm6 >> 5 == 1) + esize = ESize32; + else + assert(0 && "Wrong encoding of Inst{7:21-16}!"); + } else + esize = ESize64; + + if (NormalShift) + return esize == ESize64 ? (esize - imm6) : (2*esize - imm6); + else + return esize == ESize64 ? imm6 : (imm6 - esize); +} + +// A8.6.305 VEXT +// Imm4 = Inst{11-8} +static unsigned decodeN3VImm(uint32_t insn) { + return (insn >> 8) & 0xF; +} + +static bool DisassembleNSFormatNone(MCInst &MI, unsigned Opcode, uint32_t insn, + unsigned short NumOps, unsigned &NumOpsAdded) { + assert(0 && "Unexpected NEON Sub-Format of NSFormatNone"); + return false; +} + +// VLD* +// D[d] D[d2] ... R[addr] [TIED_TO] R[update] AM6 align(ignored) +// VLD*LN* +// D[d] D[d2] ... R[addr] R[update] AM6 align(ignored) TIED_TO ... imm(idx) +// VST* +// R[addr] [TIED_TO] R[update] AM6 align(ignored) D[d] D[d2] ... +// VST*LN* +// R[addr] R[update] AM6 align(ignored) D[d] D[d2] ... [imm(idx)] +// +// Correctly set VLD*/VST*'s TIED_TO GPR, as the asm printer needs it. +static bool DisassembleVLDSTLane0(MCInst &MI, unsigned Opcode, uint32_t insn, + unsigned short NumOps, unsigned &NumOpsAdded, bool Store, bool DblSpaced) { + + const TargetInstrDesc &TID = ARMInsts[Opcode]; + const TargetOperandInfo *OpInfo = TID.OpInfo; + + // At least one DPR register plus addressing mode #6. + assert(NumOps >= 5); + + unsigned &OpIdx = NumOpsAdded; + + OpIdx = 0; + + // We have homogeneous NEON registers for Load/Store. + unsigned RegClass = 0; + + // Double-spaced registers have increments of 2. + unsigned Inc = DblSpaced ? 2 : 1; + + unsigned Rn = decodeRn(insn); + unsigned Rm = decodeRm(insn); + unsigned Rd = decodeNEONRd(insn); + + // A7.7.1 Advanced SIMD addressing mode. + bool WB = Rm != 15; + + // LLVM Addressing Mode #6. + unsigned RmEnum = 0; + if (WB && Rm != 13) + RmEnum = getRegisterEnum(ARM::GPRRegClassID, Rm); + + if (Store) { + // Consume AddrMode6 (possible TIED_TO Rn), the DPR/QPR's, then possible + // lane index. + assert(OpIdx < NumOps && OpInfo[0].RegClass == ARM::GPRRegClassID); + MI.addOperand(MCOperand::CreateReg(getRegisterEnum(ARM::GPRRegClassID, + Rn))); + ++OpIdx; + if (TID.getOperandConstraint(OpIdx, TOI::TIED_TO) != -1) { + // TIED_TO operand. + MI.addOperand(MCOperand::CreateReg(getRegisterEnum(ARM::GPRRegClassID, + Rn))); + ++OpIdx; + } + + assert(OpIdx < NumOps && OpInfo[OpIdx].RegClass == ARM::GPRRegClassID); + MI.addOperand(MCOperand::CreateReg(RmEnum)); + ++OpIdx; + assert(OpIdx < NumOps && + OpInfo[OpIdx].RegClass == 0 && OpInfo[OpIdx+1].RegClass == 0); + MI.addOperand(MCOperand::CreateImm(ARM_AM::getAM6Opc(WB))); + MI.addOperand(MCOperand::CreateImm(0)); // Alignment ignored? + OpIdx += 2; + + assert(OpIdx < NumOps && + (OpInfo[OpIdx].RegClass == ARM::DPRRegClassID || + OpInfo[OpIdx].RegClass == ARM::QPRRegClassID)); + + RegClass = OpInfo[OpIdx].RegClass; + while (OpIdx < NumOps && OpInfo[OpIdx].RegClass == RegClass) { + if (Opcode >= ARM::VST1q16 && Opcode <= ARM::VST1q8) + MI.addOperand(MCOperand::CreateReg(getRegisterEnum(RegClass,Rd,true))); + else + MI.addOperand(MCOperand::CreateReg(getRegisterEnum(RegClass,Rd))); + Rd += Inc; + ++OpIdx; + } + + // Handle possible lane index. + if (OpIdx < NumOps && OpInfo[OpIdx].RegClass == 0 + && !OpInfo[OpIdx].isPredicate() && !OpInfo[OpIdx].isOptionalDef()) { + MI.addOperand(MCOperand::CreateImm(decodeLaneIndex(insn))); + ++OpIdx; + } + + } else { + // Consume the DPR/QPR's, AddrMode6 (possible TIED_TO Rn), possible TIED_TO + // DPR/QPR's (ignored), then possible lane index. + RegClass = OpInfo[0].RegClass; + + while (OpIdx < NumOps && OpInfo[OpIdx].RegClass == RegClass) { + if (Opcode >= ARM::VLD1q16 && Opcode <= ARM::VLD1q8) + MI.addOperand(MCOperand::CreateReg(getRegisterEnum(RegClass,Rd,true))); + else + MI.addOperand(MCOperand::CreateReg(getRegisterEnum(RegClass,Rd))); + Rd += Inc; + ++OpIdx; + } + + assert(OpIdx < NumOps && OpInfo[OpIdx].RegClass == ARM::GPRRegClassID); + MI.addOperand(MCOperand::CreateReg(getRegisterEnum(ARM::GPRRegClassID, + Rn))); + ++OpIdx; + if (TID.getOperandConstraint(OpIdx, TOI::TIED_TO) != -1) { + // TIED_TO operand. + MI.addOperand(MCOperand::CreateReg(getRegisterEnum(ARM::GPRRegClassID, + Rn))); + ++OpIdx; + } + + assert(OpIdx < NumOps && OpInfo[OpIdx].RegClass == ARM::GPRRegClassID); + MI.addOperand(MCOperand::CreateReg(RmEnum)); + ++OpIdx; + assert(OpIdx < NumOps && + OpInfo[OpIdx].RegClass == 0 && OpInfo[OpIdx+1].RegClass == 0); + MI.addOperand(MCOperand::CreateImm(ARM_AM::getAM6Opc(WB))); + MI.addOperand(MCOperand::CreateImm(0)); // Alignment ignored? + OpIdx += 2; + + while (OpIdx < NumOps && OpInfo[OpIdx].RegClass == RegClass) { + assert(TID.getOperandConstraint(OpIdx, TOI::TIED_TO) != -1); + MI.addOperand(MCOperand::CreateReg(0)); + ++OpIdx; + } + + // Handle possible lane index. + if (OpIdx < NumOps && OpInfo[OpIdx].RegClass == 0 + && !OpInfo[OpIdx].isPredicate() && !OpInfo[OpIdx].isOptionalDef()) { + MI.addOperand(MCOperand::CreateImm(decodeLaneIndex(insn))); + ++OpIdx; + } + } + + return true; +} + +// A7.7 +// If L (Inst{21}) == 0, store instructions. +// DblSpaced = false. +static bool DisassembleVLDSTLane(MCInst &MI, unsigned Opcode, uint32_t insn, + unsigned short NumOps, unsigned &NumOpsAdded) { + + return DisassembleVLDSTLane0(MI, Opcode, insn, NumOps, NumOpsAdded, + slice(insn, 21, 21) == 0, false); +} +// A7.7 +// If L (Inst{21}) == 0, store instructions. +// DblSpaced = true. +static bool DisassembleVLDSTLaneDbl(MCInst &MI, unsigned Opcode, uint32_t insn, + unsigned short NumOps, unsigned &NumOpsAdded) { + + return DisassembleVLDSTLane0(MI, Opcode, insn, NumOps, NumOpsAdded, + slice(insn, 21, 21) == 0, true); +} + +// VLDRQ (vldmia), VSTRQ (vstmia) +// Qd Rn imm (AM4) +static bool DisassembleVLDSTRQ(MCInst &MI, unsigned Opcode, uint32_t insn, + unsigned short NumOps, unsigned &NumOpsAdded) { + + const TargetOperandInfo *OpInfo = ARMInsts[Opcode].OpInfo; + + assert(NumOps >= 3 && + OpInfo[0].RegClass == ARM::QPRRegClassID && + OpInfo[1].RegClass == ARM::GPRRegClassID && + OpInfo[2].RegClass == 0); + + // Qd = Inst{22:15-12} => NEON Rd + MI.addOperand(MCOperand::CreateReg( + getRegisterEnum(ARM::QPRRegClassID, + decodeNEONRd(insn), true))); + + // Rn = Inst{19-16} => ARM Rn + MI.addOperand(MCOperand::CreateReg(getRegisterEnum(ARM::GPRRegClassID, + decodeRn(insn)))); + + // Next comes the AM4 Opcode. + assert(Opcode == ARM::VLDRQ || Opcode == ARM::VSTRQ); + ARM_AM::AMSubMode SubMode = getAMSubModeForBits(getPUBits(insn)); + bool WB = getWBit(insn) == 1; + MI.addOperand(MCOperand::CreateImm(ARM_AM::getAM4ModeImm(SubMode, WB))); + + NumOpsAdded = 3; + return true; +} + +// VMOV (immediate) +// Qd/Dd imm +static bool DisassembleNVdImm(MCInst &MI, unsigned Opcode, uint32_t insn, + unsigned short NumOps, unsigned &NumOpsAdded) { + + const TargetInstrDesc &TID = ARMInsts[Opcode]; + const TargetOperandInfo *OpInfo = TID.OpInfo; + + assert(NumOps >= 2 && + (OpInfo[0].RegClass == ARM::DPRRegClassID || + OpInfo[0].RegClass == ARM::QPRRegClassID) && + (OpInfo[1].RegClass == 0)); + + // Qd/Dd = Inst{22:15-12} => NEON Rd + MI.addOperand(MCOperand::CreateReg(getRegisterEnum(OpInfo[0].RegClass, + decodeNEONRd(insn)))); + + ElemSize esize = ESizeNA; + switch (Opcode) { + case ARM::VMOVv8i8: + case ARM::VMOVv16i8: + esize = ESize8; + break; + case ARM::VMOVv4i16: + case ARM::VMOVv8i16: + esize = ESize16; + break; + case ARM::VMOVv2i32: + case ARM::VMOVv4i32: + esize = ESize32; + break; + case ARM::VMOVv1i64: + case ARM::VMOVv2i64: + esize = ESize64; + default: + assert(0 && "Unreachable code!"); + return false; + } + + // One register and a modified immediate value. + // Add the imm operand. + MI.addOperand(MCOperand::CreateImm(decodeN1VImm(insn, esize))); + + NumOpsAdded = 2; + return true; +} + +namespace { +enum N2VFlag { + N2V_None, + N2V_VectorDupLane, + N2V_VectorShiftLeftLong, + N2V_VectorConvert_Between_Float_Fixed +}; +} // End of unnamed namespace + +// Vector Convert [between floating-point and fixed-point] +// Qd/Dd Qm/Dm [fbits] +// +// Vector Duplicate Lane (from scalar to all elements) Instructions. +// VDUPLN16d, VDUPLN16q, VDUPLN32d, VDUPLN32q, VDUPLN8d, VDUPLN8q: +// Qd/Dd Dm index +// +// Vector Shift Left Long (with maximum shift count) Instructions. +// VSHLLi16, VSHLLi32, VSHLLi8: Qd Dm imm (== size) +// +// Vector Move Long: +// Qd Dm +// +// Vector Move Narrow: +// Dd Qm +// +// Others +static bool DisassembleNVdVmImm0(MCInst &MI, unsigned Opc, uint32_t insn, + unsigned short NumOps, unsigned &NumOpsAdded, N2VFlag Flag = N2V_None) { + + const TargetInstrDesc &TID = ARMInsts[Opc]; + const TargetOperandInfo *OpInfo = TID.OpInfo; + + assert(NumOps >= 2 && + (OpInfo[0].RegClass == ARM::DPRRegClassID || + OpInfo[0].RegClass == ARM::QPRRegClassID) && + (OpInfo[1].RegClass == ARM::DPRRegClassID || + OpInfo[1].RegClass == ARM::QPRRegClassID)); + + unsigned &OpIdx = NumOpsAdded; + + OpIdx = 0; + + ElemSize esize = ESizeNA; + if (Flag == N2V_VectorShiftLeftLong) { + // VSHLL has maximum shift count as the imm, inferred from its size. + assert(Opc == ARM::VSHLLi16 || Opc == ARM::VSHLLi32 || Opc == ARM::VSHLLi8); + esize = Opc == ARM::VSHLLi8 ? ESize8 + : (Opc == ARM::VSHLLi16 ? ESize16 + : ESize32); + } + if (Flag == N2V_VectorDupLane) { + // VDUPLN has its index embedded. Its size can be inferred from the Opcode. + assert(Opc >= ARM::VDUPLN16d && Opc <= ARM::VDUPLN8q); + esize = (Opc == ARM::VDUPLN8d || Opc == ARM::VDUPLN8q) ? ESize8 + : ((Opc == ARM::VDUPLN16d || Opc == ARM::VDUPLN16q) ? ESize16 + : ESize32); + } + + // Qd/Dd = Inst{22:15-12} => NEON Rd + MI.addOperand(MCOperand::CreateReg(getRegisterEnum(OpInfo[OpIdx].RegClass, + decodeNEONRd(insn)))); + ++OpIdx; + + // VPADAL... + if (TID.getOperandConstraint(OpIdx, TOI::TIED_TO) != -1) { + // TIED_TO operand. + MI.addOperand(MCOperand::CreateReg(0)); + ++OpIdx; + } + + // Dm = Inst{5:3-0} => NEON Rm + MI.addOperand(MCOperand::CreateReg(getRegisterEnum(OpInfo[OpIdx].RegClass, + decodeNEONRm(insn)))); + ++OpIdx; + + // Add the imm operand, if required. + if (OpIdx < NumOps && OpInfo[OpIdx].RegClass == 0 + && !OpInfo[OpIdx].isPredicate() && !OpInfo[OpIdx].isOptionalDef()) { + + unsigned imm = 0xFFFFFFFF; + + if (Flag == N2V_VectorShiftLeftLong) + imm = static_cast(esize); + if (Flag == N2V_VectorDupLane) + imm = decodeNVLaneDupIndex(insn, esize); + if (Flag == N2V_VectorConvert_Between_Float_Fixed) + imm = decodeVCVTFractionBits(insn); + + assert(imm != 0xFFFFFFFF); + MI.addOperand(MCOperand::CreateImm(imm)); + ++OpIdx; + } + + return true; +} + +static bool DisassembleNVdVmImm(MCInst &MI, unsigned Opc, uint32_t insn, + unsigned short NumOps, unsigned &NumOpsAdded) { + + return DisassembleNVdVmImm0(MI, Opc, insn, NumOps, NumOpsAdded); +} +static bool DisassembleNVdVmImmVCVT(MCInst &MI, unsigned Opc, uint32_t insn, + unsigned short NumOps, unsigned &NumOpsAdded) { + + return DisassembleNVdVmImm0(MI, Opc, insn, NumOps, NumOpsAdded, + N2V_VectorConvert_Between_Float_Fixed); +} +static bool DisassembleNVdVmImmVDupLane(MCInst &MI, unsigned Opc, uint32_t insn, + unsigned short NumOps, unsigned &NumOpsAdded) { + + return DisassembleNVdVmImm0(MI, Opc, insn, NumOps, NumOpsAdded, + N2V_VectorDupLane); +} +static bool DisassembleNVdVmImmVSHLL(MCInst &MI, unsigned Opc, uint32_t insn, + unsigned short NumOps, unsigned &NumOpsAdded) { + + return DisassembleNVdVmImm0(MI, Opc, insn, NumOps, NumOpsAdded, + N2V_VectorShiftLeftLong); +} + +// Vector Transpose/Unzip/Zip Instructions +// Qd/Dd Qm/Dm [Qd/Dd (TIED_TO)] [Qm/Dm (TIED_TO)] +static bool DisassembleNVectorShuffle(MCInst &MI,unsigned Opcode,uint32_t insn, + unsigned short NumOps, unsigned &NumOpsAdded) { + + const TargetInstrDesc &TID = ARMInsts[Opcode]; + const TargetOperandInfo *OpInfo = TID.OpInfo; + + assert(NumOps >= 4 && + (OpInfo[0].RegClass == ARM::DPRRegClassID || + OpInfo[0].RegClass == ARM::QPRRegClassID) && + (OpInfo[1].RegClass == ARM::DPRRegClassID || + OpInfo[1].RegClass == ARM::QPRRegClassID) && + (OpInfo[2].RegClass == ARM::DPRRegClassID || + OpInfo[2].RegClass == ARM::QPRRegClassID) && + (OpInfo[3].RegClass == ARM::DPRRegClassID || + OpInfo[3].RegClass == ARM::QPRRegClassID)); + + unsigned &OpIdx = NumOpsAdded; + + OpIdx = 0; + + // Qd/Dd = Inst{22:15-12} => NEON Rd + MI.addOperand(MCOperand::CreateReg(getRegisterEnum(OpInfo[OpIdx].RegClass, + decodeNEONRd(insn)))); + ++OpIdx; + + // Dm = Inst{5:3-0} => NEON Rm + MI.addOperand(MCOperand::CreateReg(getRegisterEnum(OpInfo[OpIdx].RegClass, + decodeNEONRm(insn)))); + ++OpIdx; + + assert(TID.getOperandConstraint(OpIdx, TOI::TIED_TO) != -1 && + TID.getOperandConstraint(OpIdx+1, TOI::TIED_TO) != -1); + + MI.addOperand(MCOperand::CreateReg(0)); ++OpIdx; + MI.addOperand(MCOperand::CreateReg(0)); ++OpIdx; + + return true; +} + +// Vector Shift [Accumulate] Instructions. +// Qd/Dd [Qd/Dd (TIED_TO)] Qm/Dm ShiftAmt +static bool DisassembleNVectorShift0(MCInst &MI, unsigned Opcode, uint32_t insn, + unsigned short NumOps, unsigned &NumOpsAdded, bool NormalShift = true) { + + const TargetInstrDesc &TID = ARMInsts[Opcode]; + const TargetOperandInfo *OpInfo = TID.OpInfo; + + assert(NumOps >= 3 && + (OpInfo[0].RegClass == ARM::DPRRegClassID || + OpInfo[0].RegClass == ARM::QPRRegClassID) && + (OpInfo[1].RegClass == ARM::DPRRegClassID || + OpInfo[1].RegClass == ARM::QPRRegClassID)); + + unsigned &OpIdx = NumOpsAdded; + + OpIdx = 0; + + // Qd/Dd = Inst{22:15-12} => NEON Rd + MI.addOperand(MCOperand::CreateReg(getRegisterEnum(OpInfo[OpIdx].RegClass, + decodeNEONRd(insn)))); + ++OpIdx; + + if (TID.getOperandConstraint(OpIdx, TOI::TIED_TO) != -1) { + // TIED_TO operand. + MI.addOperand(MCOperand::CreateReg(0)); + ++OpIdx; + } + + assert(OpInfo[OpIdx].RegClass == ARM::DPRRegClassID || + OpInfo[OpIdx].RegClass == ARM::QPRRegClassID); + + // Qm/Dm = Inst{5:3-0} => NEON Rm + MI.addOperand(MCOperand::CreateReg(getRegisterEnum(OpInfo[OpIdx].RegClass, + decodeNEONRm(insn)))); + ++OpIdx; + + assert(OpInfo[OpIdx].RegClass == 0); + + // Add the imm operand. + MI.addOperand(MCOperand::CreateImm(decodeNVSAmt(insn, NormalShift))); + ++OpIdx; + + return true; +} + +// Normal shift amount interpretation. +static bool DisassembleNVectorShift(MCInst &MI, unsigned Opcode, uint32_t insn, + unsigned short NumOps, unsigned &NumOpsAdded) { + + return DisassembleNVectorShift0(MI, Opcode, insn, NumOps, NumOpsAdded, true); +} +// Different shift amount interpretation. +static bool DisassembleNVectorShift2(MCInst &MI, unsigned Opcode, uint32_t insn, + unsigned short NumOps, unsigned &NumOpsAdded) { + + return DisassembleNVectorShift0(MI, Opcode, insn, NumOps, NumOpsAdded, false); +} + +namespace { +enum N3VFlag { + N3V_None, + N3V_VectorExtract, + N3V_VectorShift, + N3V_Multiply_By_Scalar +}; +} // End of unnamed namespace + +// NEON Three Register Instructions with Optional Immediate Operand +// +// Vector Extract Instructions. +// Qd/Dd Qn/Dn Qm/Dm imm4 +// +// Vector Shift (Register) Instructions. +// Qd/Dd Qm/Dm Qn/Dn (notice the order of m, n) +// +// Vector Multiply [Accumulate/Subtract] [Long] By Scalar Instructions. +// Qd/Dd Qn/Dn RestrictedDm index +// +// Others +static bool DisassembleNVdVnVmImm0(MCInst &MI, unsigned Opcode, uint32_t insn, + unsigned short NumOps, unsigned &NumOpsAdded, N3VFlag Flag = N3V_None) { + + const TargetInstrDesc &TID = ARMInsts[Opcode]; + const TargetOperandInfo *OpInfo = TID.OpInfo; + + assert(NumOps >= 3 && + (OpInfo[0].RegClass == ARM::DPRRegClassID || + OpInfo[0].RegClass == ARM::QPRRegClassID) && + (OpInfo[1].RegClass == ARM::DPRRegClassID || + OpInfo[1].RegClass == ARM::QPRRegClassID) && + (OpInfo[2].RegClass != 0)); + + unsigned &OpIdx = NumOpsAdded; + + OpIdx = 0; + + bool VdVnVm = Flag == N3V_VectorShift ? false : true; + bool IsImm4 = Flag == N3V_VectorExtract ? true : false; + bool IsDmRestricted = Flag == N3V_Multiply_By_Scalar ? true : false; + ElemSize esize = ESizeNA; + if (Flag == N3V_Multiply_By_Scalar) { + unsigned size = (insn >> 20) & 3; + if (size == 1) esize = ESize16; + if (size == 2) esize = ESize32; + assert (esize == ESize16 || esize == ESize32); + } + + // Qd/Dd = Inst{22:15-12} => NEON Rd + MI.addOperand(MCOperand::CreateReg(getRegisterEnum(OpInfo[OpIdx].RegClass, + decodeNEONRd(insn)))); + ++OpIdx; + + // VABA, VABAL, VBSLd, VBSLq, ... + if (TID.getOperandConstraint(OpIdx, TOI::TIED_TO) != -1) { + // TIED_TO operand. + MI.addOperand(MCOperand::CreateReg(0)); + ++OpIdx; + } + + // Dn = Inst{7:19-16} => NEON Rn + // or + // Dm = Inst{5:3-0} => NEON Rm + MI.addOperand(MCOperand::CreateReg( + getRegisterEnum(OpInfo[OpIdx].RegClass, + VdVnVm ? decodeNEONRn(insn) + : decodeNEONRm(insn)))); + ++OpIdx; + + // Dm = Inst{5:3-0} => NEON Rm + // or + // Dm is restricted to D0-D7 if size is 16, D0-D15 otherwise + // or + // Dn = Inst{7:19-16} => NEON Rn + unsigned m = VdVnVm ? (IsDmRestricted ? decodeRestrictedDm(insn, esize) + : decodeNEONRm(insn)) + : decodeNEONRn(insn); + + MI.addOperand(MCOperand::CreateReg( + getRegisterEnum(OpInfo[OpIdx].RegClass, m))); + ++OpIdx; + + if (OpIdx < NumOps && OpInfo[OpIdx].RegClass == 0 + && !OpInfo[OpIdx].isPredicate() && !OpInfo[OpIdx].isOptionalDef()) { + // Add the imm operand. + unsigned Imm = 0; + if (IsImm4) + Imm = decodeN3VImm(insn); + else if (IsDmRestricted) + Imm = decodeRestrictedDmIndex(insn, esize); + else + assert(0 && "Internal error: unreachable code!"); + + MI.addOperand(MCOperand::CreateImm(Imm)); + ++OpIdx; + } + + return true; +} + +static bool DisassembleNVdVnVmImm(MCInst &MI, unsigned Opcode, uint32_t insn, + unsigned short NumOps, unsigned &NumOpsAdded) { + + return DisassembleNVdVnVmImm0(MI, Opcode, insn, NumOps, NumOpsAdded); +} +static bool DisassembleNVdVnVmImmVectorShift(MCInst &MI, unsigned Opcode, + uint32_t insn, unsigned short NumOps, unsigned &NumOpsAdded) { + + return DisassembleNVdVnVmImm0(MI, Opcode, insn, NumOps, NumOpsAdded, + N3V_VectorShift); +} +static bool DisassembleNVdVnVmImmVectorExtract(MCInst &MI, unsigned Opcode, + uint32_t insn, unsigned short NumOps, unsigned &NumOpsAdded) { + + return DisassembleNVdVnVmImm0(MI, Opcode, insn, NumOps, NumOpsAdded, + N3V_VectorExtract); +} +static bool DisassembleNVdVnVmImmMulScalar(MCInst &MI, unsigned Opcode, + uint32_t insn, unsigned short NumOps, unsigned &NumOpsAdded) { + + return DisassembleNVdVnVmImm0(MI, Opcode, insn, NumOps, NumOpsAdded, + N3V_Multiply_By_Scalar); +} + +// Vector Table Lookup +// +// VTBL1, VTBX1: Dd [Dd(TIED_TO)] Dn Dm +// VTBL2, VTBX2: Dd [Dd(TIED_TO)] Dn Dn+1 Dm +// VTBL3, VTBX3: Dd [Dd(TIED_TO)] Dn Dn+1 Dn+2 Dm +// VTBL4, VTBX4: Dd [Dd(TIED_TO)] Dn Dn+1 Dn+2 Dn+3 Dm +static bool DisassembleVTBL(MCInst &MI, unsigned Opcode, uint32_t insn, + unsigned short NumOps, unsigned &NumOpsAdded) { + + const TargetInstrDesc &TID = ARMInsts[Opcode]; + const TargetOperandInfo *OpInfo = TID.OpInfo; + + assert(NumOps >= 3 && + OpInfo[0].RegClass == ARM::DPRRegClassID && + OpInfo[1].RegClass == ARM::DPRRegClassID && + OpInfo[2].RegClass == ARM::DPRRegClassID); + + unsigned &OpIdx = NumOpsAdded; + + OpIdx = 0; + + unsigned Rn = decodeNEONRn(insn); + + // {Dn} encoded as len = 0b00 + // {Dn Dn+1} encoded as len = 0b01 + // {Dn Dn+1 Dn+2 } encoded as len = 0b10 + // {Dn Dn+1 Dn+2 Dn+3} encoded as len = 0b11 + unsigned Len = slice(insn, 9, 8) + 1; + + // Dd (the destination vector) + MI.addOperand(MCOperand::CreateReg(getRegisterEnum(ARM::DPRRegClassID, + decodeNEONRd(insn)))); + ++OpIdx; + + // Process tied_to operand constraint. + int Idx; + if ((Idx = TID.getOperandConstraint(OpIdx, TOI::TIED_TO)) != -1) { + MI.addOperand(MI.getOperand(Idx)); + ++OpIdx; + } + + // Do the now. + for (unsigned i = 0; i < Len; ++i) { + assert(OpIdx < NumOps && OpInfo[OpIdx].RegClass == ARM::DPRRegClassID); + MI.addOperand(MCOperand::CreateReg(getRegisterEnum(ARM::DPRRegClassID, + Rn + i))); + ++OpIdx; + } + + // Dm (the index vector) + assert(OpIdx < NumOps && OpInfo[OpIdx].RegClass == ARM::DPRRegClassID); + MI.addOperand(MCOperand::CreateReg(getRegisterEnum(ARM::DPRRegClassID, + decodeNEONRm(insn)))); + ++OpIdx; + + return true; +} + +/// NEONFuncPtrs - NEONFuncPtrs maps NSFormat to corresponding DisassembleFP. +/// We divide the disassembly task into different categories, with each one +/// corresponding to a specific instruction encoding format. There could be +/// exceptions when handling a specific format, and that is why the Opcode is +/// also present in the function prototype. +static const DisassembleFP NEONFuncPtrs[] = { + // This will assert(). + &DisassembleNSFormatNone, + + // VLD and VST (including one lane) Instructions. + &DisassembleVLDSTLane, + + // VLD and VST (including one lane) Double-Spaced Instructions. + &DisassembleVLDSTLaneDbl, + + // A8.6.319 VLDM & A8.6.399 VSTM + // LLVM defines VLDRQ/VSTRQ to load/store a Q register as a D register pair. + &DisassembleVLDSTRQ, + + // A7.4.6 One register and a modified immediate value + // 1-Register Instructions with imm. + // LLVM only defines VMOVv instructions. + &DisassembleNVdImm, + + // 2-Register Instructions with no imm. + &DisassembleNVdVmImm, + + // 2-Register Instructions with imm (vector convert float/fixed point). + &DisassembleNVdVmImmVCVT, + + // 2-Register Instructions with imm (vector dup lane). + &DisassembleNVdVmImmVDupLane, + + // 2-Register Instructions with imm (vector shift left long). + &DisassembleNVdVmImmVSHLL, + + // Vector Transpose/Unzip/Zip Instructions. + &DisassembleNVectorShuffle, + + // Vector Shift [Narrow Accumulate] Instructions. + &DisassembleNVectorShift, + + // Vector Shift Instructions with different interpretation of shift amount. + &DisassembleNVectorShift2, + + // 3-Register Data-Processing Instructions. + &DisassembleNVdVnVmImm, + + // Vector Shift (Register) Instructions. + // D:Vd M:Vm N:Vn (notice that M:Vm is the first operand) + &DisassembleNVdVnVmImmVectorShift, + + // Vector Extract Instructions. + &DisassembleNVdVnVmImmVectorExtract, + + // Vector [Saturating Rounding Doubling] Multiply [Accumulate/Subtract] [Long] + // By Scalar Instructions. + &DisassembleNVdVnVmImmMulScalar, + + // Vector Table Lookup uses byte indexes in a control vector to look up byte + // values in a table and generate a new vector. + &DisassembleVTBL, + NULL, +}; + +static bool DisassembleNEONFrm(MCInst &MI, unsigned Opcode, uint32_t insn, + unsigned short NumOps, unsigned &NumOpsAdded) { + assert(0 && "Code is not reachable"); + return false; +} + +// Vector Get Lane (move scalar to ARM core register) Instructions. +// VGETLNi32, VGETLNs16, VGETLNs8, VGETLNu16, VGETLNu8: Rt Dn index +static bool DisassembleNEONGetLnFrm(MCInst &MI, unsigned Opcode, uint32_t insn, + unsigned short NumOps, unsigned &NumOpsAdded) { + + const TargetInstrDesc &TID = ARMInsts[Opcode]; + unsigned short NumDefs = TID.getNumDefs(); + const TargetOperandInfo *OpInfo = TID.OpInfo; + + assert(NumDefs == 1 && NumOps >= 3 && + OpInfo[0].RegClass == ARM::GPRRegClassID && + OpInfo[1].RegClass == ARM::DPRRegClassID && + OpInfo[2].RegClass == 0); + + ElemSize esize = + Opcode == ARM::VGETLNi32 ? ESize32 + : ((Opcode == ARM::VGETLNs16 || Opcode == ARM::VGETLNu16) ? ESize16 + : ESize32); + + // Rt = Inst{15-12} => ARM Rd + MI.addOperand(MCOperand::CreateReg(getRegisterEnum(ARM::GPRRegClassID, + decodeRd(insn)))); + + // Dn = Inst{7:19-16} => NEON Rn + MI.addOperand(MCOperand::CreateReg(getRegisterEnum(ARM::DPRRegClassID, + decodeNEONRn(insn)))); + + MI.addOperand(MCOperand::CreateImm(decodeNVLaneOpIndex(insn, esize))); + + NumOpsAdded = 3; + return true; +} + +// Vector Set Lane (move ARM core register to scalar) Instructions. +// VSETLNi16, VSETLNi32, VSETLNi8: Dd Dd (TIED_TO) Rt index +static bool DisassembleNEONSetLnFrm(MCInst &MI, unsigned Opcode, uint32_t insn, + unsigned short NumOps, unsigned &NumOpsAdded) { + + const TargetInstrDesc &TID = ARMInsts[Opcode]; + unsigned short NumDefs = TID.getNumDefs(); + const TargetOperandInfo *OpInfo = TID.OpInfo; + + assert(NumDefs == 1 && NumOps >= 3 && + OpInfo[0].RegClass == ARM::DPRRegClassID && + OpInfo[1].RegClass == ARM::DPRRegClassID && + TID.getOperandConstraint(1, TOI::TIED_TO) != -1 && + OpInfo[2].RegClass == ARM::GPRRegClassID && + OpInfo[3].RegClass == 0); + + ElemSize esize = + Opcode == ARM::VSETLNi8 ? ESize8 + : (Opcode == ARM::VSETLNi16 ? ESize16 + : ESize32); + + // Dd = Inst{7:19-16} => NEON Rn + MI.addOperand(MCOperand::CreateReg(getRegisterEnum(ARM::DPRRegClassID, + decodeNEONRn(insn)))); + + // TIED_TO operand. + MI.addOperand(MCOperand::CreateReg(0)); + + // Rt = Inst{15-12} => ARM Rd + MI.addOperand(MCOperand::CreateReg(getRegisterEnum(ARM::GPRRegClassID, + decodeRd(insn)))); + + MI.addOperand(MCOperand::CreateImm(decodeNVLaneOpIndex(insn, esize))); + + NumOpsAdded = 4; + return true; +} + +// Vector Duplicate Instructions (from ARM core register to all elements). +// VDUP8d, VDUP16d, VDUP32d, VDUP8q, VDUP16q, VDUP32q: Qd/Dd Rt +static bool DisassembleNEONDupFrm(MCInst &MI, unsigned Opcode, uint32_t insn, + unsigned short NumOps, unsigned &NumOpsAdded) { + + const TargetOperandInfo *OpInfo = ARMInsts[Opcode].OpInfo; + + assert(NumOps >= 2 && + (OpInfo[0].RegClass == ARM::DPRRegClassID || + OpInfo[0].RegClass == ARM::QPRRegClassID) && + OpInfo[1].RegClass == ARM::GPRRegClassID); + + unsigned RegClass = OpInfo[0].RegClass; + + // Qd/Dd = Inst{7:19-16} => NEON Rn + MI.addOperand(MCOperand::CreateReg(getRegisterEnum(RegClass, + decodeNEONRn(insn)))); + + // Rt = Inst{15-12} => ARM Rd + MI.addOperand(MCOperand::CreateReg(getRegisterEnum(ARM::GPRRegClassID, + decodeRd(insn)))); + + NumOpsAdded = 2; + return true; +} + +// A8.6.41 DMB +// A8.6.42 DSB +// A8.6.49 ISB +static inline bool MemBarrierInstr(uint32_t insn) { + unsigned op7_4 = slice(insn, 7, 4); + if (slice(insn, 31, 20) == 0xf57 && (op7_4 >= 4 && op7_4 <= 6)) + return true; + + return false; +} + +static inline bool PreLoadOpcode(unsigned Opcode) { + switch(Opcode) { + case ARM::PLDi: case ARM::PLDr: + case ARM::PLDWi: case ARM::PLDWr: + case ARM::PLIi: case ARM::PLIr: + return true; + default: + return false; + } +} + +static bool DisassemblePreLoadFrm(MCInst &MI, unsigned Opcode, uint32_t insn, + unsigned short NumOps, unsigned &NumOpsAdded) { + + // Preload Data/Instruction requires either 2 or 4 operands. + // PLDi, PLDWi, PLIi: Rn [+/-]imm12 add = (U == '1') + // PLDr[a|m], PLDWr[a|m], PLIr[a|m]: Rn Rm addrmode2_opc + + MI.addOperand(MCOperand::CreateReg(getRegisterEnum(ARM::GPRRegClassID, + decodeRn(insn)))); + + if (Opcode == ARM::PLDi || Opcode == ARM::PLDWi || Opcode == ARM::PLIi) { + unsigned Imm12 = slice(insn, 11, 0); + bool Negative = getUBit(insn) == 0; + int Offset = Negative ? -1 - Imm12 : 1 * Imm12; + MI.addOperand(MCOperand::CreateImm(Offset)); + NumOpsAdded = 2; + } else { + MI.addOperand(MCOperand::CreateReg(getRegisterEnum(ARM::GPRRegClassID, + decodeRm(insn)))); + + ARM_AM::AddrOpc AddrOpcode = getUBit(insn) ? ARM_AM::add : ARM_AM::sub; + + // Inst{6-5} encodes the shift opcode. + ARM_AM::ShiftOpc ShOp = getShiftOpcForBits(slice(insn, 6, 5)); + // Inst{11-7} encodes the imm5 shift amount. + unsigned ShImm = slice(insn, 11, 7); + + // A8.4.1. Possible rrx or shift amount of 32... + getImmShiftSE(ShOp, ShImm); + MI.addOperand(MCOperand::CreateImm( + ARM_AM::getAM2Opc(AddrOpcode, ShImm, ShOp))); + NumOpsAdded = 3; + } + + return true; +} + +static bool DisassembleMiscFrm(MCInst &MI, unsigned Opcode, uint32_t insn, + unsigned short NumOps, unsigned &NumOpsAdded) { + + if (MemBarrierInstr(insn)) + return true; + + switch (Opcode) { + case ARM::CLREX: + case ARM::NOP: + case ARM::TRAP: + case ARM::YIELD: + case ARM::WFE: + case ARM::WFI: + case ARM::SEV: + case ARM::SETENDBE: + case ARM::SETENDLE: + return true; + default: + break; + } + + // CPS has a singleton $opt operand that contains the following information: + // opt{4-0} = mode from Inst{4-0} + // opt{5} = changemode from Inst{17} + // opt{8-6} = AIF from Inst{8-6} + // opt{10-9} = imod from Inst{19-18} with 0b10 as enable and 0b11 as disable + if (Opcode == ARM::CPS) { + unsigned Option = slice(insn, 4, 0) | slice(insn, 17, 17) << 5 | + slice(insn, 8, 6) << 6 | slice(insn, 19, 18) << 9; + MI.addOperand(MCOperand::CreateImm(Option)); + NumOpsAdded = 1; + return true; + } + + // DBG has its option specified in Inst{3-0}. + if (Opcode == ARM::DBG) { + MI.addOperand(MCOperand::CreateImm(slice(insn, 3, 0))); + NumOpsAdded = 1; + return true; + } + + // BKPT takes an imm32 val equal to ZeroExtend(Inst{19-8:3-0}). + if (Opcode == ARM::BKPT) { + MI.addOperand(MCOperand::CreateImm(slice(insn, 19, 8) << 4 | + slice(insn, 3, 0))); + NumOpsAdded = 1; + return true; + } + + if (PreLoadOpcode(Opcode)) + return DisassemblePreLoadFrm(MI, Opcode, insn, NumOps, NumOpsAdded); + + assert(0 && "Unexpected misc instruction!"); + return false; +} + +static bool DisassembleThumbMiscFrm(MCInst &MI, unsigned Opcode, uint32_t insn, + unsigned short NumOps, unsigned &NumOpsAdded) { + + assert(0 && "Unexpected thumb misc. instruction!"); + return false; +} + +/// FuncPtrs - FuncPtrs maps ARMFormat to its corresponding DisassembleFP. +/// We divide the disassembly task into different categories, with each one +/// corresponding to a specific instruction encoding format. There could be +/// exceptions when handling a specific format, and that is why the Opcode is +/// also present in the function prototype. +static const DisassembleFP FuncPtrs[] = { + &DisassemblePseudo, + &DisassembleMulFrm, + &DisassembleBrFrm, + &DisassembleBrMiscFrm, + &DisassembleDPFrm, + &DisassembleDPSoRegFrm, + &DisassembleLdFrm, + &DisassembleStFrm, + &DisassembleLdMiscFrm, + &DisassembleStMiscFrm, + &DisassembleLdStMulFrm, + &DisassembleArithMiscFrm, + &DisassembleExtFrm, + &DisassembleVFPUnaryFrm, + &DisassembleVFPBinaryFrm, + &DisassembleVFPConv1Frm, + &DisassembleVFPConv2Frm, + &DisassembleVFPConv3Frm, + &DisassembleVFPConv4Frm, + &DisassembleVFPConv5Frm, + &DisassembleVFPLdStFrm, + &DisassembleVFPLdStMulFrm, + &DisassembleVFPMiscFrm, + &DisassembleThumbFrm, + &DisassembleNEONFrm, + &DisassembleNEONGetLnFrm, + &DisassembleNEONSetLnFrm, + &DisassembleNEONDupFrm, + &DisassembleLdStExFrm, + &DisassembleMiscFrm, + &DisassembleThumbMiscFrm, + NULL, +}; + +/// ARMAlgorithm - ARMAlgorithm implements ARMDisassemblyAlgorithm for solving +/// the problem of building the MCOperands of an MCInst. Construction of +/// ARMAlgorithm requires passing in a function pointer with the DisassembleFP +/// data type. +class ARMAlgorithm : public ARMDisassemblyAlgorithm { + /// Algorithms - Algorithms stores a map from Format to ARMAlgorithm*. + static std::vector Algorithms; + /// NSAlgorithms - NSAlgorithms stores a map from NSFormat to ARMAlgorithm*. + static std::vector NSAlgorithms; + + DisassembleFP Disassemble; + +public: + /// GetInstance - GetInstance returns an instance of ARMAlgorithm given the + /// encoding Format. API clients should not free up the returned instance. + static ARMAlgorithm *GetInstance(ARMFormat Format, NSFormat NSF) { + /// Init the first time. + if (Algorithms.size() == 0) { + Algorithms.resize(array_lengthof(FuncPtrs)); + for (unsigned i = 0, num = array_lengthof(FuncPtrs); i < num; ++i) + if (FuncPtrs[i]) + Algorithms[i] = new ARMAlgorithm(FuncPtrs[i]); + else + Algorithms[i] = NULL; + } + if (NSAlgorithms.size() == 0) { + NSAlgorithms.resize(array_lengthof(NEONFuncPtrs)); + for (unsigned i = 0, num = array_lengthof(NEONFuncPtrs); i < num; ++i) + if (NEONFuncPtrs[i]) + NSAlgorithms[i] = new ARMAlgorithm(NEONFuncPtrs[i]); + else + NSAlgorithms[i] = NULL; + } + + if (Format != ARM_FORMAT_NEONFRM) + return Algorithms[Format]; + else + return NSAlgorithms[NSF]; + } + + virtual bool Solve(MCInst &MI, unsigned Opcode, uint32_t insn, + unsigned short NumOps, unsigned &NumOpsAdded) const { + if (Disassemble == NULL) + return false; + + return (*Disassemble)(MI, Opcode, insn, NumOps, NumOpsAdded); + } + +private: + ARMAlgorithm(DisassembleFP fp) : + ARMDisassemblyAlgorithm(), Disassemble(fp) {} + + ARMAlgorithm(ARMAlgorithm &AA) : + ARMDisassemblyAlgorithm(), Disassemble(AA.Disassemble) {} + + virtual ~ARMAlgorithm() {} +}; + +// Define the symbol here. +std::vector ARMAlgorithm::Algorithms; + +// Define the symbol here. +std::vector ARMAlgorithm::NSAlgorithms; + +// Define the symbol here. +unsigned ARMBasicMCBuilder::ITCounter = 0; + +// Define the symbol here. +unsigned ARMBasicMCBuilder::ITState = 0; + +// A8.6.50 +static unsigned short CountITSize(unsigned ITMask) { + // First count the trailing zeros of the IT mask. + unsigned TZ = CountTrailingZeros_32(ITMask); + assert(TZ <= 3); + return (4 - TZ); +} + +/// BuildIt - BuildIt performs the build step for this ARM Basic MC Builder. +/// The general idea is to set the Opcode for the MCInst, followed by adding +/// the appropriate MCOperands to the MCInst. ARM Basic MC Builder delegates +/// to the Algo (ARM Disassemble Algorithm) object to perform Format-specific +/// disassembly, followed by class method TryPredicateAndSBitModifier() to do +/// PredicateOperand and OptionalDefOperand which follow the Dst/Src Operands. +bool ARMBasicMCBuilder::BuildIt(MCInst &MI, uint32_t insn) { + // Stage 1 sets the Opcode. + MI.setOpcode(Opcode); + // If the number of operands is zero, we're done! + if (NumOps == 0) + return true; + + // Stage 2 calls the ARM Disassembly Algorithm to build the operand list. + unsigned NumOpsAdded = 0; + bool OK = Algo.Solve(MI, Opcode, insn, NumOps, NumOpsAdded); + + if (!OK) return false; + if (NumOpsAdded >= NumOps) + return true; + + // Stage 3 deals with operands unaccounted for after stage 2 is finished. + // FIXME: Should this be done selectively? + return TryPredicateAndSBitModifier(MI, Opcode, insn, NumOps - NumOpsAdded); +} + +bool ARMBasicMCBuilder::TryPredicateAndSBitModifier(MCInst& MI, unsigned Opcode, + uint32_t insn, unsigned short NumOpsRemaining) { + + assert(NumOpsRemaining > 0); + + const TargetOperandInfo *OpInfo = ARMInsts[Opcode].OpInfo; + const std::string &Name = ARMInsts[Opcode].Name; + unsigned Idx = MI.getNumOperands(); + + // First, we check whether this instr specifies the PredicateOperand through + // a pair of TargetOperandInfos with isPredicate() property. + if (NumOpsRemaining >= 2 && + OpInfo[Idx].isPredicate() && OpInfo[Idx+1].isPredicate() && + OpInfo[Idx].RegClass == 0 && OpInfo[Idx+1].RegClass == ARM::CCRRegClassID) + { + // If we are inside an IT block, get the IT condition bits maintained via + // ARMBasicMCBuilder::ITState[7:0], through ARMBasicMCBuilder::GetITCond(). + // See also A2.5.2. + if (InITBlock()) + MI.addOperand(MCOperand::CreateImm(GetITCond())); + else { + if (Name.length() > 1 && Name[0] == 't') { + // Thumb conditional branch instructions have their cond field embedded, + // like ARM. + // + // A8.6.16 B + if (Name == "t2Bcc") + MI.addOperand(MCOperand::CreateImm(slice(insn, 25, 22))); + else if (Name == "tBcc") + MI.addOperand(MCOperand::CreateImm(slice(insn, 11, 8))); + else + MI.addOperand(MCOperand::CreateImm(ARMCC::AL)); + } else { + // ARM Instructions. Check condition field. + int64_t CondVal = getCondField(insn); + if (CondVal == 0xF) + MI.addOperand(MCOperand::CreateImm(ARMCC::AL)); + else + MI.addOperand(MCOperand::CreateImm(CondVal)); + } + } + MI.addOperand(MCOperand::CreateReg(ARM::CPSR)); + Idx += 2; + NumOpsRemaining -= 2; + if (NumOpsRemaining == 0) + return true; + } + + assert(NumOpsRemaining > 0); + + // Next, if OptionalDefOperand exists, we check whether the 'S' bit is set. + if (OpInfo[Idx].isOptionalDef() && OpInfo[Idx].RegClass==ARM::CCRRegClassID) { + MI.addOperand(MCOperand::CreateReg(getSBit(insn) == 1 ? ARM::CPSR : 0)); + --NumOpsRemaining; + } + + if (NumOpsRemaining == 0) + return true; + else + return false; +} + +/// RunBuildAfterHook - RunBuildAfterHook performs operations deemed necessary +/// after BuildIt is finished. +bool ARMBasicMCBuilder::RunBuildAfterHook(bool Status, MCInst &MI, + uint32_t insn) { + + if (Opcode == ARM::t2IT) { + ARMBasicMCBuilder::ITCounter = CountITSize(slice(insn, 3, 0)); + ARMBasicMCBuilder::InitITState(slice(insn, 7, 0)); + } else if (InITBlock()) + ARMBasicMCBuilder::UpdateITState(); + + return Status; +} + +AbstractARMMCBuilder *ARMMCBuilderFactory::CreateMCBuilder(unsigned Opcode, + ARMFormat Format, NSFormat NSF) { + + ARMAlgorithm *Algo = ARMAlgorithm::GetInstance(Format, NSF); + if (!Algo) + return NULL; + + return new ARMBasicMCBuilder(Opcode, Format, NSF, + ARMInsts[Opcode].getNumOperands(), *Algo); +} Added: llvm/trunk/lib/Target/ARM/Disassembler/ARMDisassemblerCore.h URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Target/ARM/Disassembler/ARMDisassemblerCore.h?rev=98637&view=auto ============================================================================== --- llvm/trunk/lib/Target/ARM/Disassembler/ARMDisassemblerCore.h (added) +++ llvm/trunk/lib/Target/ARM/Disassembler/ARMDisassemblerCore.h Tue Mar 16 11:36:54 2010 @@ -0,0 +1,301 @@ +//===- ARMDisassemblerCore.h - ARM disassembler helpers ----*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file is part of the ARM Disassembler. +// +// The first part defines the enumeration type of ARM instruction format, which +// specifies the encoding used by the instruction, as well as a helper function +// to convert the enums to printable char strings. +// +// It also contains code to represent the concepts of Builder, Builder Factory, +// as well as the Algorithm to solve the problem of disassembling an ARM instr. +// +//===----------------------------------------------------------------------===// + +#ifndef ARMDISASSEMBLERCORE_H +#define ARMDISASSEMBLERCORE_H + +#include "llvm/MC/MCInst.h" +#include "llvm/Target/TargetInstrInfo.h" +#include "ARMInstrInfo.h" + +namespace llvm { + +class ARMUtils { +public: + static const char *OpcodeName(unsigned Opcode); +}; + +#define ARM_FORMATS \ + ENTRY(ARM_FORMAT_PSEUDO, 0) \ + ENTRY(ARM_FORMAT_MULFRM, 1) \ + ENTRY(ARM_FORMAT_BRFRM, 2) \ + ENTRY(ARM_FORMAT_BRMISCFRM, 3) \ + ENTRY(ARM_FORMAT_DPFRM, 4) \ + ENTRY(ARM_FORMAT_DPSOREGFRM, 5) \ + ENTRY(ARM_FORMAT_LDFRM, 6) \ + ENTRY(ARM_FORMAT_STFRM, 7) \ + ENTRY(ARM_FORMAT_LDMISCFRM, 8) \ + ENTRY(ARM_FORMAT_STMISCFRM, 9) \ + ENTRY(ARM_FORMAT_LDSTMULFRM, 10) \ + ENTRY(ARM_FORMAT_ARITHMISCFRM, 11) \ + ENTRY(ARM_FORMAT_EXTFRM, 12) \ + ENTRY(ARM_FORMAT_VFPUNARYFRM, 13) \ + ENTRY(ARM_FORMAT_VFPBINARYFRM, 14) \ + ENTRY(ARM_FORMAT_VFPCONV1FRM, 15) \ + ENTRY(ARM_FORMAT_VFPCONV2FRM, 16) \ + ENTRY(ARM_FORMAT_VFPCONV3FRM, 17) \ + ENTRY(ARM_FORMAT_VFPCONV4FRM, 18) \ + ENTRY(ARM_FORMAT_VFPCONV5FRM, 19) \ + ENTRY(ARM_FORMAT_VFPLDSTFRM, 20) \ + ENTRY(ARM_FORMAT_VFPLDSTMULFRM, 21) \ + ENTRY(ARM_FORMAT_VFPMISCFRM, 22) \ + ENTRY(ARM_FORMAT_THUMBFRM, 23) \ + ENTRY(ARM_FORMAT_NEONFRM, 24) \ + ENTRY(ARM_FORMAT_NEONGETLNFRM, 25) \ + ENTRY(ARM_FORMAT_NEONSETLNFRM, 26) \ + ENTRY(ARM_FORMAT_NEONDUPFRM, 27) \ + ENTRY(ARM_FORMAT_LDSTEXFRM, 28) \ + ENTRY(ARM_FORMAT_MISCFRM, 29) \ + ENTRY(ARM_FORMAT_THUMBMISCFRM, 30) + +// ARM instruction format specifies the encoding used by the instruction. +#define ENTRY(n, v) n = v, +typedef enum { + ARM_FORMATS + ARM_FORMAT_NA +} ARMFormat; +#undef ENTRY + +// Converts enum to const char*. +static const inline char *stringForARMFormat(ARMFormat form) { +#define ENTRY(n, v) case n: return #n; + switch(form) { + ARM_FORMATS + case ARM_FORMAT_NA: + default: + return ""; + } +#undef ENTRY +} + +#define NS_FORMATS \ + ENTRY(NS_FORMAT_NONE, 0) \ + ENTRY(NS_FORMAT_VLDSTLane, 1) \ + ENTRY(NS_FORMAT_VLDSTLaneDbl, 2) \ + ENTRY(NS_FORMAT_VLDSTRQ, 3) \ + ENTRY(NS_FORMAT_NVdImm, 4) \ + ENTRY(NS_FORMAT_NVdVmImm, 5) \ + ENTRY(NS_FORMAT_NVdVmImmVCVT, 6) \ + ENTRY(NS_FORMAT_NVdVmImmVDupLane, 7) \ + ENTRY(NS_FORMAT_NVdVmImmVSHLL, 8) \ + ENTRY(NS_FORMAT_NVectorShuffle, 9) \ + ENTRY(NS_FORMAT_NVectorShift, 10) \ + ENTRY(NS_FORMAT_NVectorShift2, 11) \ + ENTRY(NS_FORMAT_NVdVnVmImm, 12) \ + ENTRY(NS_FORMAT_NVdVnVmImmVectorShift, 13) \ + ENTRY(NS_FORMAT_NVdVnVmImmVectorExtract, 14) \ + ENTRY(NS_FORMAT_NVdVnVmImmMulScalar, 15) \ + ENTRY(NS_FORMAT_VTBL, 16) + +// NEON instruction sub-format further classify the NEONFrm instruction. +#define ENTRY(n, v) n = v, +typedef enum { + NS_FORMATS + NS_FORMAT_NA +} NSFormat; +#undef ENTRY + +// Converts enum to const char*. +static const inline char *stringForNSFormat(NSFormat form) { +#define ENTRY(n, v) case n: return #n; + switch(form) { + NS_FORMATS + case NS_FORMAT_NA: + return "NA"; + default: + return ""; + } +#undef ENTRY +} + +/// Expands on the enum definitions from ARMBaseInstrInfo.h. +/// They are being used by the disassembler implementation. +namespace ARMII { + enum { + NEONRegMask = 15, + GPRRegMask = 15, + NEON_RegRdShift = 12, + NEON_D_BitShift = 22, + NEON_RegRnShift = 16, + NEON_N_BitShift = 7, + NEON_RegRmShift = 0, + NEON_M_BitShift = 5 + }; +} + +/// Utility function for extracting [From, To] bits from a uint32_t. +static inline unsigned slice(uint32_t Bits, unsigned From, unsigned To) { + assert(From < 32 && To < 32 && From >= To); + return (Bits >> To) & ((1 << (From - To + 1)) - 1); +} + +/// Utility function for setting [From, To] bits to Val for a uint32_t. +static inline void setSlice(uint32_t &Bits, unsigned From, unsigned To, + uint32_t Val) { + assert(From < 32 && To < 32 && From >= To); + uint32_t Mask = ((1 << (From - To + 1)) - 1); + Bits &= ~(Mask << To); + Bits |= (Val & Mask) << To; +} + +/// Various utilities for checking the target specific flags. + +/// A unary data processing instruction doesn't have an Rn operand. +static inline bool isUnaryDP(unsigned TSFlags) { + return (TSFlags & ARMII::UnaryDP); +} + +/// This four-bit field describes the addressing mode used. +/// See also ARMBaseInstrInfo.h. +static inline unsigned getAddrMode(unsigned TSFlags) { + return (TSFlags & ARMII::AddrModeMask); +} + +/// {IndexModePre, IndexModePost} +/// Only valid for load and store ops. +/// See also ARMBaseInstrInfo.h. +static inline unsigned getIndexMode(unsigned TSFlags) { + return (TSFlags & ARMII::IndexModeMask) >> ARMII::IndexModeShift; +} + +/// Pre-/post-indexed operations define an extra $base_wb in the OutOperandList. +static inline bool isPrePostLdSt(unsigned TSFlags) { + return (TSFlags & ARMII::IndexModeMask) != 0; +} + +/// AbstractARMMCBuilder - AbstractARMMCBuilder represents an interface of ARM +/// MCInst builder that knows how to build up the MCOperand list. +class AbstractARMMCBuilder { +public: + /// Build - Build the MCInst fully and return true. Return false if any + /// failure occurs. + virtual bool Build(MCInst &MI, uint32_t insn) { return false; } +}; + +/// ARMDisassemblyAlgorithm - ARMDisassemblyAlgorithm represents an interface of +/// ARM disassembly algorithm that relies on the entries of target operand info, +/// among other things, to solve the problem of disassembling an ARM machine +/// instruction. +class ARMDisassemblyAlgorithm { +public: + /// Return true if this algorithm successfully disassembles the instruction. + /// NumOpsAdded is updated to reflect the number of operands added by the + /// algorithm. NumOpsAdded may be less than NumOps, in which case, there are + /// operands unaccounted for which need to be dealt with by the API client. + virtual bool Solve(MCInst& MI, unsigned Opcode, uint32_t insn, + unsigned short NumOps, unsigned &NumOpsAdded) const + = 0; +}; + +/// ARMBasicMCBuilder - ARMBasicMCBuilder represents a concrete subclass of +/// ARMAbstractMCBuilder. +class ARMBasicMCBuilder : public AbstractARMMCBuilder { + unsigned Opcode; + ARMFormat Format; + NSFormat NSF; + unsigned short NumOps; + const ARMDisassemblyAlgorithm &Algo; + static unsigned ITCounter; // Possible values: 0, 1, 2, 3, 4. + static unsigned ITState; // A2.5.2 Consists of IT[7:5] and IT[4:0] initially. + +public: + ARMBasicMCBuilder(ARMBasicMCBuilder &MCB) : AbstractARMMCBuilder(), + Opcode(MCB.Opcode), Format(MCB.Format), NSF(MCB.NSF), NumOps(MCB.NumOps), + Algo(MCB.Algo) {} + + /// Opcode, Format, NSF, NumOperands, and Algo make an ARM Basic MCBuilder. + ARMBasicMCBuilder(unsigned opc, ARMFormat format, NSFormat NSF, + unsigned short num, const ARMDisassemblyAlgorithm &algo) + : AbstractARMMCBuilder(), Opcode(opc), Format(format), NumOps(num), + Algo(algo) {} + + /// TryPredicateAndSBitModifier - TryPredicateAndSBitModifier tries to process + /// the possible Predicate and SBitModifier, to build the remaining MCOperand + /// constituents. + static bool TryPredicateAndSBitModifier(MCInst& MI, unsigned Opcode, + uint32_t insn, unsigned short NumOpsRemaning); + + /// InITBlock - InITBlock returns true if we are inside an IT block. + static bool InITBlock() { + return ITCounter > 0; + } + + /// Build - Build delegates to BuildIt to perform the heavy liftling. After + /// that, it invokes RunBuildAfterHook where some housekeepings can be done. + virtual bool Build(MCInst &MI, uint32_t insn) { + bool Status = BuildIt(MI, insn); + return RunBuildAfterHook(Status, MI, insn); + } + + /// BuildIt - BuildIt performs the build step for this ARM Basic MC Builder. + /// The general idea is to set the Opcode for the MCInst, followed by adding + /// the appropriate MCOperands to the MCInst. ARM Basic MC Builder delegates + /// to the Algo (ARM Disassemble Algorithm) object to perform Format-specific + /// disassembly, followed by class method TryPredicateAndSBitModifier() to do + /// PredicateOperand and OptionalDefOperand which follow the Dst/Src Operands. + virtual bool BuildIt(MCInst &MI, uint32_t insn); + + /// RunBuildAfterHook - RunBuildAfterHook performs operations deemed necessary + /// after BuildIt is finished. + virtual bool RunBuildAfterHook(bool Status, MCInst &MI, uint32_t insn); + +private: + /// Get condition of the current IT instruction. + static unsigned GetITCond() { + return slice(ITState, 7, 4); + } + + /// Init ITState. + static void InitITState(unsigned short bits7_0) { + ITState = bits7_0; + } + + /// Update ITState if necessary. + static void UpdateITState() { + assert(ITCounter); + --ITCounter; + if (ITCounter == 0) + ITState = 0; + else { + unsigned short NewITState4_0 = slice(ITState, 4, 0) << 1; + setSlice(ITState, 4, 0, NewITState4_0); + } + } +}; + +/// ARMMCBuilderFactory - ARMMCBuilderFactory represents the factory class that +/// vends out ARMAbstractMCBuilder instances through its class method. +class ARMMCBuilderFactory { +private: + ARMMCBuilderFactory(); // DO NOT IMPLEMENT. + +public: + /// CreateMCBuilder - Return an AbstractARMMCBuilder that can build up the MC + /// infrastructure of an MCInst given the Opcode and Format of the instr. + /// Return NULL if it fails to create/return a proper builder. API clients + /// are responsible for freeing up of the allocated memory. Cacheing can be + /// performed by the API clients to improve performance. + static AbstractARMMCBuilder *CreateMCBuilder(unsigned Opcode, + ARMFormat Format, NSFormat NSF); +}; + +} // namespace llvm + +#endif Added: llvm/trunk/lib/Target/ARM/Disassembler/Makefile URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Target/ARM/Disassembler/Makefile?rev=98637&view=auto ============================================================================== --- llvm/trunk/lib/Target/ARM/Disassembler/Makefile (added) +++ llvm/trunk/lib/Target/ARM/Disassembler/Makefile Tue Mar 16 11:36:54 2010 @@ -0,0 +1,17 @@ +##===- lib/Target/ARM/Disassembler/Makefile ----------------*- Makefile -*-===## +# +# The LLVM Compiler Infrastructure +# +# This file is distributed under the University of Illinois Open Source +# License. See LICENSE.TXT for details. +# +##===----------------------------------------------------------------------===## + +LEVEL = ../../../.. +LIBRARYNAME = LLVMARMDisassembler +CXXFLAGS = -fno-rtti + +# Hack: we need to include 'main' arm target directory to grab private headers +CPPFLAGS = -I$(PROJ_OBJ_DIR)/.. -I$(PROJ_SRC_DIR)/.. + +include $(LEVEL)/Makefile.common Added: llvm/trunk/lib/Target/ARM/Disassembler/ThumbDisassemblerCore.cpp.inc URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Target/ARM/Disassembler/ThumbDisassemblerCore.cpp.inc?rev=98637&view=auto ============================================================================== --- llvm/trunk/lib/Target/ARM/Disassembler/ThumbDisassemblerCore.cpp.inc (added) +++ llvm/trunk/lib/Target/ARM/Disassembler/ThumbDisassemblerCore.cpp.inc Tue Mar 16 11:36:54 2010 @@ -0,0 +1,2158 @@ +//===- ThumbDisassemblerCore.cpp - ARM disassembler helpers ----*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file is part of the ARM Disassembler. +// It contains code for disassembling a Thumb instr. +// +//===----------------------------------------------------------------------===// + +/////////////////////////////// +// // +// Utility Functions // +// // +/////////////////////////////// + +// Utilities for 16-bit Thumb instructions. +/* +15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0 + [ tRt ] + [ tRm ] [ tRn ] [ tRd ] + D [ Rm ] [ Rd ] + + [ imm3] + [ imm5 ] + i [ imm5 ] + [ imm7 ] + [ imm8 ] + [ imm11 ] + + [ cond ] +*/ + +static bool InITBlock() { + return ARMBasicMCBuilder::InITBlock(); +} + +// Extract tRt: Inst{10-8}. +static inline unsigned getT1tRt(uint32_t insn) { + return slice(insn, 10, 8); +} + +// Extract tRm: Inst{8-6}. +static inline unsigned getT1tRm(uint32_t insn) { + return slice(insn, 8, 6); +} + +// Extract tRn: Inst{5-3}. +static inline unsigned getT1tRn(uint32_t insn) { + return slice(insn, 5, 3); +} + +// Extract tRd: Inst{2-0}. +static inline unsigned getT1tRd(uint32_t insn) { + return slice(insn, 2, 0); +} + +// Extract [D:Rd]: Inst{7:2-0}. +static inline unsigned getT1Rd(uint32_t insn) { + return slice(insn, 7, 7) << 3 | slice(insn, 2, 0); +} + +// Extract Rm: Inst{6-3}. +static inline unsigned getT1Rm(uint32_t insn) { + return slice(insn, 6, 3); +} + +// Extract imm3: Inst{8-6}. +static inline unsigned getT1Imm3(uint32_t insn) { + return slice(insn, 8, 6); +} + +// Extract imm5: Inst{10-6}. +static inline unsigned getT1Imm5(uint32_t insn) { + return slice(insn, 10, 6); +} + +// Extract i:imm5: Inst{9:7-3}. +static inline unsigned getT1Imm6(uint32_t insn) { + return slice(insn, 9, 9) << 5 | slice(insn, 7, 3); +} + +// Extract imm7: Inst{6-0}. +static inline unsigned getT1Imm7(uint32_t insn) { + return slice(insn, 6, 0); +} + +// Extract imm8: Inst{7-0}. +static inline unsigned getT1Imm8(uint32_t insn) { + return slice(insn, 7, 0); +} + +// Extract imm11: Inst{10-0}. +static inline unsigned getT1Imm11(uint32_t insn) { + return slice(insn, 10, 0); +} + +// Extract cond: Inst{11-8}. +static inline unsigned getT1Cond(uint32_t insn) { + return slice(insn, 11, 8); +} + +static inline bool IsGPR(unsigned RegClass) { + return RegClass == ARM::GPRRegClassID; +} + +// Utilities for 32-bit Thumb instructions. + +// Extract imm4: Inst{19-16}. +static inline unsigned getImm4(uint32_t insn) { + return slice(insn, 19, 16); +} + +// Extract imm3: Inst{14-12}. +static inline unsigned getImm3(uint32_t insn) { + return slice(insn, 14, 12); +} + +// Extract imm8: Inst{7-0}. +static inline unsigned getImm8(uint32_t insn) { + return slice(insn, 7, 0); +} + +// A8.6.61 LDRB (immediate, Thumb) and friends +// +/-: Inst{9} +// imm8: Inst{7-0} +static inline int decodeImm8(uint32_t insn) { + int Offset = getImm8(insn); + return slice(insn, 9, 9) ? Offset : -Offset; +} + +// Extract imm12: Inst{11-0}. +static inline unsigned getImm12(uint32_t insn) { + return slice(insn, 11, 0); +} + +// A8.6.63 LDRB (literal) and friends +// +/-: Inst{23} +// imm12: Inst{11-0} +static inline int decodeImm12(uint32_t insn) { + int Offset = getImm12(insn); + return slice(insn, 23, 23) ? Offset : -Offset; +} + +// Extract imm2: Inst{7-6}. +static inline unsigned getImm2(uint32_t insn) { + return slice(insn, 7, 6); +} + +// For BFI, BFC, t2SBFX, and t2UBFX. +// Extract lsb: Inst{14-12:7-6}. +static inline unsigned getLsb(uint32_t insn) { + return getImm3(insn) << 2 | getImm2(insn); +} + +// For BFI and BFC. +// Extract msb: Inst{4-0}. +static inline unsigned getMsb(uint32_t insn) { + return slice(insn, 4, 0); +} + +// For t2SBFX and t2UBFX. +// Extract widthminus1: Inst{4-0}. +static inline unsigned getWidthMinus1(uint32_t insn) { + return slice(insn, 4, 0); +} + +// For t2ADDri12 and t2SUBri12. +// imm12 = i:imm3:imm8; +static inline unsigned getIImm3Imm8(uint32_t insn) { + return slice(insn, 26, 26) << 11 | getImm3(insn) << 8 | getImm8(insn); +} + +// For t2MOVi16 and t2MOVTi16. +// imm16 = imm4:i:imm3:imm8; +static inline unsigned getImm16(uint32_t insn) { + return getImm4(insn) << 12 | slice(insn, 26, 26) << 11 | + getImm3(insn) << 8 | getImm8(insn); +} + +// Inst{5-4} encodes the shift type. +static inline unsigned getShiftTypeBits(uint32_t insn) { + return slice(insn, 5, 4); +} + +// Inst{14-12}:Inst{7-6} encodes the imm5 shift amount. +static inline unsigned getShiftAmtBits(uint32_t insn) { + return getImm3(insn) << 2 | getImm2(insn); +} + +// A8.6.17 BFC +// Encoding T1 ARMv6T2, ARMv7 +// LLVM-specific encoding for # and # +static inline uint32_t getBitfieldInvMask(uint32_t insn) { + uint32_t lsb = getImm3(insn) << 2 | getImm2(insn); + uint32_t msb = getMsb(insn); + uint32_t Val = 0; + assert(lsb <= msb && "Encoding error: lsb > msb"); + for (uint32_t i = lsb; i <= msb; ++i) + Val |= (1 << i); + return ~Val; +} + +// A8.4 Shifts applied to a register +// A8.4.1 Constant shifts +// A8.4.3 Pseudocode details of instruction-specified shifts and rotates +// +// decodeImmShift() returns the shift amount and the the shift opcode. +// Note that, as of Jan-06-2010, LLVM does not support rrx shifted operands yet. +static inline unsigned decodeImmShift(unsigned bits2, unsigned imm5, + ARM_AM::ShiftOpc &ShOp) { + + assert(imm5 < 32); + switch (bits2) { + default: assert(0 && "No such value"); + case 0: + ShOp = ARM_AM::lsl; + return imm5; + case 1: + ShOp = ARM_AM::lsr; + return (imm5 == 0 ? 32 : imm5); + case 2: + ShOp = ARM_AM::asr; + return (imm5 == 0 ? 32 : imm5); + case 3: + ShOp = (imm5 == 0 ? ARM_AM::rrx : ARM_AM::ror); + return (imm5 == 0 ? 1 : imm5); + } +} + +// A6.3.2 Modified immediate constants in Thumb instructions +// +// ThumbExpandImm() returns the modified immediate constant given an imm12 for +// Thumb data-processing instructions with modified immediate. +// See also A6.3.1 Data-processing (modified immediate). +static inline unsigned ThumbExpandImm(unsigned imm12) { + assert(imm12 <= 0xFFF); + + // If the leading two bits is 0b00, the modified immediate constant is + // obtained by splatting the low 8 bits into the first byte, every other byte, + // or every byte of a 32-bit value. + // + // Otherwise, a rotate right of '1':imm12<6:0> by the amount imm12<11:7> is + // performed. + + if (slice(imm12, 11, 10) == 0) { + unsigned short control = slice(imm12, 9, 8); + unsigned imm8 = slice(imm12, 7, 0); + switch (control) { + default: + assert(0 && "No such value"); + return 0; + case 0: + return imm8; + case 1: + return imm8 << 16 | imm8; + case 2: + return imm8 << 24 | imm8 << 8; + case 3: + return imm8 << 24 | imm8 << 16 | imm8 << 8 | imm8; + } + } else { + // A rotate is required. + unsigned Val = 1 << 7 | slice(imm12, 6, 0); + unsigned Amt = slice(imm12, 11, 7); + return ARM_AM::rotr32(Val, Amt); + } +} + +static inline int decodeImm32_B_EncodingT3(uint32_t insn) { + bool S = slice(insn, 26, 26); + bool J1 = slice(insn, 13, 13); + bool J2 = slice(insn, 11, 11); + unsigned Imm21 = slice(insn, 21, 16) << 12 | slice(insn, 10, 0) << 1; + if (S) Imm21 |= 1 << 20; + if (J2) Imm21 |= 1 << 19; + if (J1) Imm21 |= 1 << 18; + + return signextend(Imm21); +} + +static inline int decodeImm32_B_EncodingT4(uint32_t insn) { + unsigned S = slice(insn, 26, 26); + bool I1 = slice(insn, 13, 13) == S; + bool I2 = slice(insn, 11, 11) == S; + unsigned Imm25 = slice(insn, 25, 16) << 12 | slice(insn, 10, 0) << 1; + if (S) Imm25 |= 1 << 24; + if (I1) Imm25 |= 1 << 23; + if (I2) Imm25 |= 1 << 22; + + return signextend(Imm25); +} + +static inline int decodeImm32_BL(uint32_t insn) { + unsigned S = slice(insn, 26, 26); + bool I1 = slice(insn, 13, 13) == S; + bool I2 = slice(insn, 11, 11) == S; + unsigned Imm25 = slice(insn, 25, 16) << 12 | slice(insn, 10, 0) << 1; + if (S) Imm25 |= 1 << 24; + if (I1) Imm25 |= 1 << 23; + if (I2) Imm25 |= 1 << 22; + + return signextend(Imm25); +} + +static inline int decodeImm32_BLX(uint32_t insn) { + unsigned S = slice(insn, 26, 26); + bool I1 = slice(insn, 13, 13) == S; + bool I2 = slice(insn, 11, 11) == S; + unsigned Imm25 = slice(insn, 25, 16) << 12 | slice(insn, 10, 1) << 2; + if (S) Imm25 |= 1 << 24; + if (I1) Imm25 |= 1 << 23; + if (I2) Imm25 |= 1 << 22; + + return signextend(Imm25); +} + +// See, for example, A8.6.221 SXTAB16. +static inline unsigned decodeRotate(uint32_t insn) { + unsigned rotate = slice(insn, 5, 4); + return rotate << 3; +} + +/////////////////////////////////////////////// +// // +// Thumb1 instruction disassembly functions. // +// // +/////////////////////////////////////////////// + +// See "Utilities for 16-bit Thumb instructions" for register naming convention. + +// A6.2.1 Shift (immediate), add, subtract, move, and compare +// +// shift immediate: tRd CPSR tRn imm5 +// add/sub register: tRd CPSR tRn tRm +// add/sub 3-bit immediate: tRd CPSR tRn imm3 +// add/sub 8-bit immediate: tRt CPSR tRt(TIED_TO) imm8 +// mov/cmp immediate: tRt [CPSR] imm8 (CPSR present for mov) +// +// Special case: +// tMOVSr: tRd tRn +static bool DisassembleThumb1General(MCInst &MI, unsigned Opcode, uint32_t insn, + unsigned short NumOps, unsigned &NumOpsAdded) { + + const TargetOperandInfo *OpInfo = ARMInsts[Opcode].OpInfo; + unsigned &OpIdx = NumOpsAdded; + + OpIdx = 0; + + assert(NumOps >= 2 && OpInfo[0].RegClass == ARM::tGPRRegClassID); + + bool Imm3 = (Opcode == ARM::tADDi3 || Opcode == ARM::tSUBi3); + + // Use Rt implies use imm8. + bool UseRt = (Opcode == ARM::tADDi8 || Opcode == ARM::tSUBi8 || + Opcode == ARM::tMOVi8 || Opcode == ARM::tCMPi8); + + // Add the destination operand. + MI.addOperand(MCOperand::CreateReg( + getRegisterEnum(ARM::tGPRRegClassID, + UseRt ? getT1tRt(insn) : getT1tRd(insn)))); + ++OpIdx; + + // Check whether the next operand to be added is a CCR Register. + if (OpInfo[OpIdx].RegClass == ARM::CCRRegClassID) { + assert(OpInfo[OpIdx].isOptionalDef()); + MI.addOperand(MCOperand::CreateReg(InITBlock() ? 0 : ARM::CPSR)); + ++OpIdx; + } + + // Check whether the next operand to be added is a Thumb1 Register. + assert(OpIdx < NumOps); + if (OpInfo[OpIdx].RegClass == ARM::tGPRRegClassID) { + // For UseRt, the reg operand is tied to the first reg operand. + MI.addOperand(MCOperand::CreateReg( + getRegisterEnum(ARM::tGPRRegClassID, + UseRt ? getT1tRt(insn) : getT1tRn(insn)))); + ++OpIdx; + } + + // Special case for tMOVSr. + if (OpIdx == NumOps) + return true; + + // The next available operand is either a reg operand or an imm operand. + if (OpInfo[OpIdx].RegClass == ARM::tGPRRegClassID) { + // Three register operand instructions. + MI.addOperand(MCOperand::CreateReg(getRegisterEnum(ARM::tGPRRegClassID, + getT1tRm(insn)))); + } else { + assert(OpInfo[OpIdx].RegClass == 0 && + !OpInfo[OpIdx].isPredicate() && !OpInfo[OpIdx].isOptionalDef()); + MI.addOperand(MCOperand::CreateImm(UseRt ? getT1Imm8(insn) + : (Imm3 ? getT1Imm3(insn) + : getT1Imm5(insn)))); + } + ++OpIdx; + + return true; +} + +// A6.2.2 Data-processing +// +// tCMPr, tTST, tCMN: tRd tRn +// tMVN, tRSB: tRd CPSR tRn +// Others: tRd CPSR tRd(TIED_TO) tRn +static bool DisassembleThumb1DP(MCInst &MI, unsigned Opcode, uint32_t insn, + unsigned short NumOps, unsigned &NumOpsAdded) { + + const TargetInstrDesc &TID = ARMInsts[Opcode]; + const TargetOperandInfo *OpInfo = TID.OpInfo; + unsigned &OpIdx = NumOpsAdded; + + OpIdx = 0; + + assert(NumOps >= 2 && OpInfo[0].RegClass == ARM::tGPRRegClassID && + (OpInfo[1].RegClass == ARM::CCRRegClassID + || OpInfo[1].RegClass == ARM::tGPRRegClassID)); + + // Add the destination operand. + MI.addOperand(MCOperand::CreateReg(getRegisterEnum(ARM::tGPRRegClassID, + getT1tRd(insn)))); + ++OpIdx; + + // Check whether the next operand to be added is a CCR Register. + if (OpInfo[OpIdx].RegClass == ARM::CCRRegClassID) { + assert(OpInfo[OpIdx].isOptionalDef()); + MI.addOperand(MCOperand::CreateReg(InITBlock() ? 0 : ARM::CPSR)); + ++OpIdx; + } + + // We have either { tRd(TIED_TO), tRn } or { tRn } remaining. + // Process the TIED_TO operand first. + + assert(OpIdx < NumOps && OpInfo[OpIdx].RegClass == ARM::tGPRRegClassID); + int Idx; + if ((Idx = TID.getOperandConstraint(OpIdx, TOI::TIED_TO)) != -1) { + // The reg operand is tied to the first reg operand. + MI.addOperand(MI.getOperand(Idx)); + ++OpIdx; + } + + // Process possible next reg operand. + if (OpIdx < NumOps && OpInfo[OpIdx].RegClass == ARM::tGPRRegClassID) { + // Add tRn operand. + MI.addOperand(MCOperand::CreateReg(getRegisterEnum(ARM::tGPRRegClassID, + getT1tRn(insn)))); + ++OpIdx; + } + + return true; +} + +// A6.2.3 Special data instructions and branch and exchange +// +// tADDhirr: Rd Rd(TIED_TO) Rm +// tCMPhir: Rd Rm +// tMOVr, tMOVgpr2gpr, tMOVgpr2tgpr, tMOVtgpr2gpr: Rd|tRd Rm|tRn +// tBX_RET: 0 operand +// tBX_RET_vararg: Rm +// tBLXr_r9: Rm +static bool DisassembleThumb1Special(MCInst &MI, unsigned Opcode, uint32_t insn, + unsigned short NumOps, unsigned &NumOpsAdded) { + + // tBX_RET has 0 operand. + if (NumOps == 0) + return true; + + // BX/BLX has 1 reg operand: Rm. + if (NumOps == 1) { + MI.addOperand(MCOperand::CreateReg(getRegisterEnum(ARM::GPRRegClassID, + getT1Rm(insn)))); + NumOpsAdded = 1; + return true; + } + + const TargetInstrDesc &TID = ARMInsts[Opcode]; + const TargetOperandInfo *OpInfo = TID.OpInfo; + unsigned &OpIdx = NumOpsAdded; + + OpIdx = 0; + + // Add the destination operand. + unsigned RegClass = OpInfo[OpIdx].RegClass; + MI.addOperand(MCOperand::CreateReg( + getRegisterEnum(RegClass, + IsGPR(RegClass) ? getT1Rd(insn) + : getT1tRd(insn)))); + ++OpIdx; + + // We have either { Rd(TIED_TO), Rm } or { Rm|tRn } remaining. + // Process the TIED_TO operand first. + + assert(OpIdx < NumOps); + int Idx; + if ((Idx = TID.getOperandConstraint(OpIdx, TOI::TIED_TO)) != -1) { + // The reg operand is tied to the first reg operand. + MI.addOperand(MI.getOperand(Idx)); + ++OpIdx; + } + + // The next reg operand is either Rm or tRn. + assert(OpIdx < NumOps); + RegClass = OpInfo[OpIdx].RegClass; + MI.addOperand(MCOperand::CreateReg( + getRegisterEnum(RegClass, + IsGPR(RegClass) ? getT1Rm(insn) + : getT1tRn(insn)))); + ++OpIdx; + + return true; +} + +// A8.6.59 LDR (literal) +// +// tLDRpci: tRt imm8*4 +static bool DisassembleThumb1LdPC(MCInst &MI, unsigned Opcode, uint32_t insn, + unsigned short NumOps, unsigned &NumOpsAdded) { + + const TargetOperandInfo *OpInfo = ARMInsts[Opcode].OpInfo; + + assert(NumOps >= 2 && OpInfo[0].RegClass == ARM::tGPRRegClassID && + (OpInfo[1].RegClass == 0 && + !OpInfo[1].isPredicate() && + !OpInfo[1].isOptionalDef())); + + // Add the destination operand. + MI.addOperand(MCOperand::CreateReg(getRegisterEnum(ARM::tGPRRegClassID, + getT1tRt(insn)))); + + // And the (imm8 << 2) operand. + MI.addOperand(MCOperand::CreateImm(getT1Imm8(insn) << 2)); + + NumOpsAdded = 2; + + return true; +} + +// Thumb specific addressing modes (see ARMInstrThumb.td): +// +// t_addrmode_rr := reg + reg +// +// t_addrmode_s4 := reg + reg +// reg + imm5 * 4 +// +// t_addrmode_s2 := reg + reg +// reg + imm5 * 2 +// +// t_addrmode_s1 := reg + reg +// reg + imm5 +// +// t_addrmode_sp := sp + imm8 * 4 +// + +// A6.2.4 Load/store single data item +// +// Load/Store Register (reg|imm): tRd tRn imm5 tRm +// Load Register Signed Byte|Halfword: tRd tRn tRm +static bool DisassembleThumb1LdSt(unsigned opA, MCInst &MI, unsigned Opcode, + uint32_t insn, unsigned short NumOps, unsigned &NumOpsAdded) { + + const TargetInstrDesc &TID = ARMInsts[Opcode]; + const TargetOperandInfo *OpInfo = TID.OpInfo; + unsigned &OpIdx = NumOpsAdded; + + // Table A6-5 16-bit Thumb Load/store instructions + // opA = 0b0101 for STR/LDR (register) and friends. + // Otherwise, we have STR/LDR (immediate) and friends. + bool Imm5 = (opA != 5); + + assert(NumOps >= 2 + && OpInfo[0].RegClass == ARM::tGPRRegClassID + && OpInfo[1].RegClass == ARM::tGPRRegClassID); + + // Add the destination reg and the base reg. + MI.addOperand(MCOperand::CreateReg(getRegisterEnum(ARM::tGPRRegClassID, + getT1tRd(insn)))); + MI.addOperand(MCOperand::CreateReg(getRegisterEnum(ARM::tGPRRegClassID, + getT1tRn(insn)))); + OpIdx = 2; + + // We have either { imm5, tRm } or { tRm } remaining. + // Process the imm5 first. Note that STR/LDR (register) should skip the imm5 + // offset operand for t_addrmode_s[1|2|4]. + + assert(OpIdx < NumOps); + + if (OpInfo[OpIdx].RegClass == 0 && !OpInfo[OpIdx].isPredicate() && + !OpInfo[OpIdx].isOptionalDef()) { + + MI.addOperand(MCOperand::CreateImm(Imm5 ? getT1Imm5(insn) : 0)); + ++OpIdx; + } + + // The next reg operand is tRm, the offset. + assert(OpIdx < NumOps && OpInfo[OpIdx].RegClass == ARM::tGPRRegClassID); + MI.addOperand(MCOperand::CreateReg(Imm5 ? 0 + : getRegisterEnum(ARM::tGPRRegClassID, + getT1tRm(insn)))); + ++OpIdx; + + return true; +} + +// A6.2.4 Load/store single data item +// +// Load/Store Register SP relative: tRt ARM::SP imm8 +static bool DisassembleThumb1LdStSP(MCInst &MI, unsigned Opcode, uint32_t insn, + unsigned short NumOps, unsigned &NumOpsAdded) { + + assert(Opcode == ARM::tLDRspi || Opcode == ARM::tSTRspi); + + const TargetOperandInfo *OpInfo = ARMInsts[Opcode].OpInfo; + + assert(NumOps >= 3 && + OpInfo[0].RegClass == ARM::tGPRRegClassID && + OpInfo[1].RegClass == ARM::GPRRegClassID && + (OpInfo[2].RegClass == 0 && + !OpInfo[2].isPredicate() && + !OpInfo[2].isOptionalDef())); + + MI.addOperand(MCOperand::CreateReg(getRegisterEnum(ARM::tGPRRegClassID, + getT1tRt(insn)))); + MI.addOperand(MCOperand::CreateReg(ARM::SP)); + MI.addOperand(MCOperand::CreateImm(getT1Imm8(insn))); + NumOpsAdded = 3; + return true; +} + +// Table A6-1 16-bit Thumb instruction encoding +// A8.6.10 ADR +// +// tADDrPCi: tRt imm8 +static bool DisassembleThumb1AddPCi(MCInst &MI, unsigned Opcode, uint32_t insn, + unsigned short NumOps, unsigned &NumOpsAdded) { + + assert(Opcode == ARM::tADDrPCi); + + const TargetOperandInfo *OpInfo = ARMInsts[Opcode].OpInfo; + + assert(NumOps >= 2 && OpInfo[0].RegClass == ARM::tGPRRegClassID && + (OpInfo[1].RegClass == 0 && + !OpInfo[1].isPredicate() && + !OpInfo[1].isOptionalDef())); + + MI.addOperand(MCOperand::CreateReg(getRegisterEnum(ARM::tGPRRegClassID, + getT1tRt(insn)))); + MI.addOperand(MCOperand::CreateImm(getT1Imm8(insn))); + NumOpsAdded = 2; + return true; +} + +// Table A6-1 16-bit Thumb instruction encoding +// A8.6.8 ADD (SP plus immediate) +// +// tADDrSPi: tRt ARM::SP imm8 +static bool DisassembleThumb1AddSPi(MCInst &MI, unsigned Opcode, uint32_t insn, + unsigned short NumOps, unsigned &NumOpsAdded) { + + assert(Opcode == ARM::tADDrSPi); + + const TargetOperandInfo *OpInfo = ARMInsts[Opcode].OpInfo; + + assert(NumOps >= 3 && + OpInfo[0].RegClass == ARM::tGPRRegClassID && + OpInfo[1].RegClass == ARM::GPRRegClassID && + (OpInfo[2].RegClass == 0 && + !OpInfo[2].isPredicate() && + !OpInfo[2].isOptionalDef())); + + MI.addOperand(MCOperand::CreateReg(getRegisterEnum(ARM::tGPRRegClassID, + getT1tRt(insn)))); + MI.addOperand(MCOperand::CreateReg(ARM::SP)); + MI.addOperand(MCOperand::CreateImm(getT1Imm8(insn))); + NumOpsAdded = 3; + return true; +} + +// tPUSH, tPOP: Pred-Imm Pred-CCR register_list +// +// where register_list = low registers + [lr] for PUSH or +// low registers + [pc] for POP +// +// "low registers" is specified by Inst{7-0} +// lr|pc is specified by Inst{8} +static bool DisassembleThumb1PushPop(MCInst &MI, unsigned Opcode, uint32_t insn, + unsigned short NumOps, unsigned &NumOpsAdded) { + + assert(Opcode == ARM::tPUSH || Opcode == ARM::tPOP); + + unsigned &OpIdx = NumOpsAdded; + + // Handling the two predicate operands before the reglist. + MI.addOperand(MCOperand::CreateImm(ARMCC::AL)); + MI.addOperand(MCOperand::CreateReg(ARM::CPSR)); + OpIdx = 2; + + // Fill the variadic part of reglist. + unsigned RegListBits = slice(insn, 8, 8) << (Opcode == ARM::tPUSH ? 14 : 15) + | slice(insn, 7, 0); + for (unsigned i = 0; i < 16; ++i) { + if ((RegListBits >> i) & 1) { + MI.addOperand(MCOperand::CreateReg(getRegisterEnum(ARM::GPRRegClassID, + i))); + ++OpIdx; + } + } + + return true; +} + +// A6.2.5 Miscellaneous 16-bit instructions +// Delegate to DisassembleThumb1PushPop() for tPUSH & tPOP. +// +// tADDspi, tSUBspi: ARM::SP ARM::SP(TIED_TO) imm7 +// t2IT: firstcond=Inst{7-4} mask=Inst{3-0} +// tCBNZ, tCBZ: tRd imm6*2 +// tBKPT: imm8 +// tNOP, tSEV, tYIELD, tWFE, tWFI: +// no operand (except predicate pair) +// tSETENDBE, tSETENDLE, : +// no operand +// Others: tRd tRn +static bool DisassembleThumb1Misc(MCInst &MI, unsigned Opcode, uint32_t insn, + unsigned short NumOps, unsigned &NumOpsAdded) { + + if (NumOps == 0) + return true; + + if (Opcode == ARM::tPUSH || Opcode == ARM::tPOP) + return DisassembleThumb1PushPop(MI, Opcode, insn, NumOps, NumOpsAdded); + + const TargetOperandInfo *OpInfo = ARMInsts[Opcode].OpInfo; + + // Predicate operands are handled elsewhere. + if (NumOps == 2 && + OpInfo[0].isPredicate() && OpInfo[1].isPredicate() && + OpInfo[0].RegClass == 0 && OpInfo[1].RegClass == ARM::CCRRegClassID) { + return true; + } + + if (Opcode == ARM::tADDspi || Opcode == ARM::tSUBspi) { + // Special case handling for tADDspi and tSUBspi. + // A8.6.8 ADD (SP plus immediate) & A8.6.215 SUB (SP minus immediate) + MI.addOperand(MCOperand::CreateReg(ARM::SP)); + MI.addOperand(MCOperand::CreateReg(ARM::SP)); + MI.addOperand(MCOperand::CreateImm(getT1Imm7(insn))); + NumOpsAdded = 3; + return true; + } + + if (Opcode == ARM::t2IT) { + // Special case handling for If-Then. + // A8.6.50 IT + // Tag the (firstcond[0] bit << 4) along with mask. + + // firstcond + MI.addOperand(MCOperand::CreateImm(slice(insn, 7, 4))); + + // firstcond[0] and mask + MI.addOperand(MCOperand::CreateImm(slice(insn, 4, 0))); + NumOpsAdded = 2; + return true; + } + + if (Opcode == ARM::tBKPT) { + MI.addOperand(MCOperand::CreateImm(getT1Imm8(insn))); // breakpoint value + NumOpsAdded = 1; + return true; + } + + // CPS has a singleton $opt operand that contains the following information: + // opt{4-0} = don't care + // opt{5} = 0 (false) + // opt{8-6} = AIF from Inst{2-0} + // opt{10-9} = 1:imod from Inst{4} with 0b10 as enable and 0b11 as disable + if (Opcode == ARM::tCPS) { + unsigned Option = slice(insn, 2, 0) << 6 | slice(insn, 4, 4) << 9 | 1 << 10; + MI.addOperand(MCOperand::CreateImm(Option)); + NumOpsAdded = 1; + return true; + } + + assert(NumOps >= 2 && OpInfo[0].RegClass == ARM::tGPRRegClassID && + (OpInfo[1].RegClass==0 || OpInfo[1].RegClass==ARM::tGPRRegClassID)); + + // Add the destination operand. + MI.addOperand(MCOperand::CreateReg(getRegisterEnum(ARM::tGPRRegClassID, + getT1tRd(insn)))); + + if (OpInfo[1].RegClass == ARM::tGPRRegClassID) { + // Two register instructions. + MI.addOperand(MCOperand::CreateReg(getRegisterEnum(ARM::tGPRRegClassID, + getT1tRn(insn)))); + } else { + // CBNZ, CBZ + assert(Opcode == ARM::tCBNZ || Opcode == ARM::tCBZ); + MI.addOperand(MCOperand::CreateImm(getT1Imm6(insn) * 2)); + } + + NumOpsAdded = 2; + + return true; +} + +// A8.6.53 LDM / LDMIA +// A8.6.189 STM / STMIA +// +// tRt AM4ModeImm Pred-Imm Pred-CCR register_list +static bool DisassembleThumb1LdStMul(bool Ld, MCInst &MI, unsigned Opcode, + uint32_t insn, unsigned short NumOps, unsigned &NumOpsAdded) { + + assert(Opcode == ARM::tLDM || Opcode == ARM::tSTM_UPD); + + unsigned &OpIdx = NumOpsAdded; + + unsigned tRt = getT1tRt(insn); + unsigned RegListBits = slice(insn, 7, 0); + + OpIdx = 0; + + // For STM, WB is always true. + if (Opcode == ARM::tSTM_UPD) { + MI.addOperand(MCOperand::CreateReg(getRegisterEnum(ARM::GPRRegClassID, + tRt))); + ++OpIdx; + } + + MI.addOperand(MCOperand::CreateReg(getRegisterEnum(ARM::GPRRegClassID, + tRt))); + ++OpIdx; + + // A8.6.53 LDM / LDMIA / LDMFD - Encoding T1 + // WB is true if tRt is not specified as a member of the register list. + // For STM, WB is always true. + bool WB = Ld ? ((RegListBits >> tRt) & 1) == 0 : true; + MI.addOperand(MCOperand::CreateImm(ARM_AM::getAM4ModeImm(ARM_AM::ia, WB))); + ++OpIdx; + + // Handling the two predicate operands before the reglist. + MI.addOperand(MCOperand::CreateImm(ARMCC::AL)); + MI.addOperand(MCOperand::CreateReg(ARM::CPSR)); + OpIdx += 2; + + // Fill the variadic part of reglist. + for (unsigned i = 0; i < 8; ++i) { + if ((RegListBits >> i) & 1) { + MI.addOperand(MCOperand::CreateReg(getRegisterEnum(ARM::tGPRRegClassID, + i))); + ++OpIdx; + } + } + + return true; +} + +static bool DisassembleThumb1LdMul(MCInst &MI, unsigned Opcode, uint32_t insn, + unsigned short NumOps, unsigned &NumOpsAdded) { + return DisassembleThumb1LdStMul(true, MI, Opcode, insn, NumOps, NumOpsAdded); +} + +static bool DisassembleThumb1StMul(MCInst &MI, unsigned Opcode, uint32_t insn, + unsigned short NumOps, unsigned &NumOpsAdded) { + return DisassembleThumb1LdStMul(false, MI, Opcode, insn, NumOps, NumOpsAdded); +} + +// A8.6.16 B Encoding T1 +// cond = Inst{11-8} & imm8 = Inst{7-0} +// imm32 = SignExtend(imm8:'0', 32) +// +// tBcc: offset Pred-Imm Pred-CCR +// tSVC: imm8 Pred-Imm Pred-CCR +// tTRAP: 0 operand (early return) +static bool DisassembleThumb1CondBr(MCInst &MI, unsigned Opcode, uint32_t insn, + unsigned short NumOps, unsigned &NumOpsAdded) { + + if (Opcode == ARM::tTRAP) + return true; + + const TargetOperandInfo *OpInfo = ARMInsts[Opcode].OpInfo; + assert(NumOps == 3 && OpInfo[0].RegClass == 0 && + OpInfo[1].isPredicate() && OpInfo[2].RegClass == ARM::CCRRegClassID); + + unsigned Imm8 = getT1Imm8(insn); + MI.addOperand(MCOperand::CreateImm( + Opcode == ARM::tBcc ? signextend(Imm8 << 1) + 4 + : (int)Imm8)); + + // Predicate operands by ARMBasicMCBuilder::TryPredicateAndSBitModifier(). + NumOpsAdded = 1; + + return true; +} + +// A8.6.16 B Encoding T2 +// imm11 = Inst{10-0} +// imm32 = SignExtend(imm11:'0', 32) +// +// tB: offset +static bool DisassembleThumb1Br(MCInst &MI, unsigned Opcode, uint32_t insn, + unsigned short NumOps, unsigned &NumOpsAdded) { + + const TargetOperandInfo *OpInfo = ARMInsts[Opcode].OpInfo; + assert(NumOps == 1 && OpInfo[0].RegClass == 0); + + unsigned Imm11 = getT1Imm11(insn); + + // When executing a Thumb instruction, PC reads as the address of the current + // instruction plus 4. The assembler subtracts 4 from the difference between + // the branch instruction and the target address, disassembler has to add 4 to + // to compensate. + MI.addOperand(MCOperand::CreateImm( + signextend(Imm11 << 1) + 4)); + + NumOpsAdded = 1; + + return true; + +} + +// See A6.2 16-bit Thumb instruction encoding for instruction classes +// corresponding to op. +// +// Table A6-1 16-bit Thumb instruction encoding (abridged) +// op Instruction or instruction class +// ------ -------------------------------------------------------------------- +// 00xxxx Shift (immediate), add, subtract, move, and compare on page A6-7 +// 010000 Data-processing on page A6-8 +// 010001 Special data instructions and branch and exchange on page A6-9 +// 01001x Load from Literal Pool, see LDR (literal) on page A8-122 +// 0101xx Load/store single data item on page A6-10 +// 011xxx +// 100xxx +// 10100x Generate PC-relative address, see ADR on page A8-32 +// 10101x Generate SP-relative address, see ADD (SP plus immediate) on page A8-28 +// 1011xx Miscellaneous 16-bit instructions on page A6-11 +// 11000x Store multiple registers, see STM / STMIA / STMEA on page A8-374 +// 11001x Load multiple registers, see LDM / LDMIA / LDMFD on page A8-110 a +// 1101xx Conditional branch, and Supervisor Call on page A6-13 +// 11100x Unconditional Branch, see B on page A8-44 +// +static bool DisassembleThumb1(uint16_t op, + MCInst &MI, unsigned Opcode, uint32_t insn, + unsigned short NumOps, unsigned &NumOpsAdded) { + + unsigned op1 = slice(op, 5, 4); + unsigned op2 = slice(op, 3, 2); + unsigned op3 = slice(op, 1, 0); + unsigned opA = slice(op, 5, 2); + switch (op1) { + case 0: + // A6.2.1 Shift (immediate), add, subtract, move, and compare + return DisassembleThumb1General(MI, Opcode, insn, NumOps, NumOpsAdded); + case 1: + switch (op2) { + case 0: + switch (op3) { + case 0: + // A6.2.2 Data-processing + return DisassembleThumb1DP(MI, Opcode, insn, NumOps, NumOpsAdded); + case 1: + // A6.2.3 Special data instructions and branch and exchange + return DisassembleThumb1Special(MI, Opcode, insn, NumOps, NumOpsAdded); + default: + // A8.6.59 LDR (literal) + return DisassembleThumb1LdPC(MI, Opcode, insn, NumOps, NumOpsAdded); + } + break; + default: + // A6.2.4 Load/store single data item + return DisassembleThumb1LdSt(opA, MI, Opcode, insn, NumOps, NumOpsAdded); + break; + } + break; + case 2: + switch (op2) { + case 0: + // A6.2.4 Load/store single data item + return DisassembleThumb1LdSt(opA, MI, Opcode, insn, NumOps, NumOpsAdded); + case 1: + // A6.2.4 Load/store single data item + return DisassembleThumb1LdStSP(MI, Opcode, insn, NumOps, NumOpsAdded); + case 2: + if (op3 <= 1) { + // A8.6.10 ADR + return DisassembleThumb1AddPCi(MI, Opcode, insn, NumOps, NumOpsAdded); + } else { + // A8.6.8 ADD (SP plus immediate) + return DisassembleThumb1AddSPi(MI, Opcode, insn, NumOps, NumOpsAdded); + } + default: + // A6.2.5 Miscellaneous 16-bit instructions + return DisassembleThumb1Misc(MI, Opcode, insn, NumOps, NumOpsAdded); + } + break; + case 3: + switch (op2) { + case 0: + if (op3 <= 1) { + // A8.6.189 STM / STMIA / STMEA + return DisassembleThumb1StMul(MI, Opcode, insn, NumOps, NumOpsAdded); + } else { + // A8.6.53 LDM / LDMIA / LDMFD + return DisassembleThumb1LdMul(MI, Opcode, insn, NumOps, NumOpsAdded); + } + case 1: + // A6.2.6 Conditional branch, and Supervisor Call + return DisassembleThumb1CondBr(MI, Opcode, insn, NumOps, NumOpsAdded); + case 2: + // Unconditional Branch, see B on page A8-44 + return DisassembleThumb1Br(MI, Opcode, insn, NumOps, NumOpsAdded); + default: + assert(0 && "Unreachable code"); + break; + } + break; + default: + assert(0 && "Unreachable code"); + break; + } + + return false; +} + +/////////////////////////////////////////////// +// // +// Thumb2 instruction disassembly functions. // +// // +/////////////////////////////////////////////// + +/////////////////////////////////////////////////////////// +// // +// Note: the register naming follows the ARM convention! // +// // +/////////////////////////////////////////////////////////// + +static inline bool Thumb2SRSOpcode(unsigned Opcode) { + switch (Opcode) { + default: + return false; + case ARM::t2SRSDBW: case ARM::t2SRSDB: + case ARM::t2SRSIAW: case ARM::t2SRSIA: + return true; + } +} + +static inline bool Thumb2RFEOpcode(unsigned Opcode) { + switch (Opcode) { + default: + return false; + case ARM::t2RFEDBW: case ARM::t2RFEDB: + case ARM::t2RFEIAW: case ARM::t2RFEIA: + return true; + } +} + +// t2SRS[IA|DB]W/t2SRS[IA|DB]: mode_imm = Inst{4-0} +static bool DisassembleThumb2SRS(MCInst &MI, unsigned Opcode, uint32_t insn, + unsigned short NumOps, unsigned &NumOpsAdded) { + MI.addOperand(MCOperand::CreateImm(slice(insn, 4, 0))); + NumOpsAdded = 1; + return true; +} + +// t2RFE[IA|DB]W/t2RFE[IA|DB]: Rn +static bool DisassembleThumb2RFE(MCInst &MI, unsigned Opcode, uint32_t insn, + unsigned short NumOps, unsigned &NumOpsAdded) { + MI.addOperand(MCOperand::CreateReg(getRegisterEnum(ARM::GPRRegClassID, + decodeRn(insn)))); + NumOpsAdded = 1; + return true; +} + +static bool DisassembleThumb2LdStMul(MCInst &MI, unsigned Opcode, uint32_t insn, + unsigned short NumOps, unsigned &NumOpsAdded) { + + if (Thumb2SRSOpcode(Opcode)) + return DisassembleThumb2SRS(MI, Opcode, insn, NumOps, NumOpsAdded); + + if (Thumb2RFEOpcode(Opcode)) + return DisassembleThumb2RFE(MI, Opcode, insn, NumOps, NumOpsAdded); + + assert(Opcode == ARM::t2LDM || Opcode == ARM::t2LDM_UPD || + Opcode == ARM::t2STM || Opcode == ARM::t2STM_UPD); + assert(NumOps >= 5 && "Thumb2 LdStMul expects NumOps of 5"); + + unsigned &OpIdx = NumOpsAdded; + + OpIdx = 0; + + unsigned Base = getRegisterEnum(ARM::GPRRegClassID, decodeRn(insn)); + + // Writeback to base. + if (Opcode == ARM::t2LDM_UPD || Opcode == ARM::t2STM_UPD) { + MI.addOperand(MCOperand::CreateReg(Base)); + ++OpIdx; + } + + MI.addOperand(MCOperand::CreateReg(Base)); + ++OpIdx; + + ARM_AM::AMSubMode SubMode = getAMSubModeForBits(getPUBits(insn)); + bool WB = getWBit(insn) == 1; + MI.addOperand(MCOperand::CreateImm(ARM_AM::getAM4ModeImm(SubMode, WB))); + ++OpIdx; + + // Handling the two predicate operands before the reglist. + MI.addOperand(MCOperand::CreateImm(ARMCC::AL)); + MI.addOperand(MCOperand::CreateReg(ARM::CPSR)); + OpIdx += 2; + + // Fill the variadic part of reglist. + unsigned RegListBits = insn & ((1 << 16) - 1); + for (unsigned i = 0; i < 16; ++i) { + if ((RegListBits >> i) & 1) { + MI.addOperand(MCOperand::CreateReg(getRegisterEnum(ARM::GPRRegClassID, + i))); + ++OpIdx; + } + } + + return true; +} + +// t2LDREX: Rd Rn +// t2LDREXD: Rd Rs Rn +// t2LDREXB, t2LDREXH: Rd Rn +// t2STREX: Rs Rd Rn +// t2STREXD: Rm Rd Rs Rn +// t2STREXB, t2STREXH: Rm Rd Rn +static bool DisassembleThumb2LdStEx(MCInst &MI, unsigned Opcode, uint32_t insn, + unsigned short NumOps, unsigned &NumOpsAdded) { + + const TargetOperandInfo *OpInfo = ARMInsts[Opcode].OpInfo; + unsigned &OpIdx = NumOpsAdded; + + OpIdx = 0; + + assert(NumOps >= 2 + && OpInfo[0].RegClass == ARM::GPRRegClassID + && OpInfo[1].RegClass == ARM::GPRRegClassID); + + bool isStore = (ARM::t2STREX <= Opcode && Opcode <= ARM::t2STREXH); + bool isSW = (Opcode == ARM::t2LDREX || Opcode == ARM::t2STREX); + bool isDW = (Opcode == ARM::t2LDREXD || Opcode == ARM::t2STREXD); + + // Add the destination operand for store. + if (isStore) { + MI.addOperand(MCOperand::CreateReg( + getRegisterEnum(ARM::GPRRegClassID, + isSW ? decodeRs(insn) : decodeRm(insn)))); + ++OpIdx; + } + + // Source operand for store and destination operand for load. + MI.addOperand(MCOperand::CreateReg(getRegisterEnum(ARM::GPRRegClassID, + decodeRd(insn)))); + ++OpIdx; + + // Thumb2 doubleword complication: with an extra source/destination operand. + if (isDW) { + MI.addOperand(MCOperand::CreateReg(getRegisterEnum(ARM::GPRRegClassID, + decodeRs(insn)))); + ++OpIdx; + } + + // Finally add the pointer operand. + MI.addOperand(MCOperand::CreateReg(getRegisterEnum(ARM::GPRRegClassID, + decodeRn(insn)))); + ++OpIdx; + + return true; +} + +// LLVM, as of Jan-05-2010, does not output , i.e., Rs, in the asm. +// Whereas the ARM Arch. Manual does not require that t2 = t+1 like in ARM ISA. +// +// t2LDRDi8: Rd Rs Rn imm8s4 (offset mode) +// t2LDRDpci: Rd Rs imm8s4 (Not decoded, prefer the generic t2LDRDi8 version) +// t2STRDi8: Rd Rs Rn imm8s4 (offset mode) +// +// Ditto for t2LDRD_PRE, t2LDRD_POST, t2STRD_PRE, t2STRD_POST, which are for +// disassembly only and do not have a tied_to writeback base register operand. +static bool DisassembleThumb2LdStDual(MCInst &MI, unsigned Opcode, + uint32_t insn, unsigned short NumOps, unsigned &NumOpsAdded) { + + const TargetOperandInfo *OpInfo = ARMInsts[Opcode].OpInfo; + + assert(NumOps >= 4 + && OpInfo[0].RegClass == ARM::GPRRegClassID + && OpInfo[1].RegClass == ARM::GPRRegClassID + && OpInfo[2].RegClass == ARM::GPRRegClassID + && OpInfo[3].RegClass == 0); + + // Add the operands. + MI.addOperand(MCOperand::CreateReg(getRegisterEnum(ARM::GPRRegClassID, + decodeRd(insn)))); + MI.addOperand(MCOperand::CreateReg(getRegisterEnum(ARM::GPRRegClassID, + decodeRs(insn)))); + MI.addOperand(MCOperand::CreateReg(getRegisterEnum(ARM::GPRRegClassID, + decodeRn(insn)))); + + // Finally add (+/-)imm8*4, depending on the U bit. + int Offset = getImm8(insn) * 4; + if (getUBit(insn) == 0) + Offset = -Offset; + MI.addOperand(MCOperand::CreateImm(Offset)); + NumOpsAdded = 4; + + return true; +} + +// PC-based defined for Codegen, which do not get decoded by design: +// +// t2TBB, t2TBH: Rm immDontCare immDontCare +// +// Generic version defined for disassembly: +// +// t2TBBgen, t2TBHgen: Rn Rm Pred-Imm Pred-CCR +static bool DisassembleThumb2TB(MCInst &MI, unsigned Opcode, + uint32_t insn, unsigned short NumOps, unsigned &NumOpsAdded) { + + assert(NumOps >= 2); + + // The generic version of TBB/TBH needs a base register. + MI.addOperand(MCOperand::CreateReg(getRegisterEnum(ARM::GPRRegClassID, + decodeRn(insn)))); + // Add the index register. + MI.addOperand(MCOperand::CreateReg(getRegisterEnum(ARM::GPRRegClassID, + decodeRm(insn)))); + NumOpsAdded = 2; + + return true; +} + +static inline bool Thumb2ShiftOpcode(unsigned Opcode) { + switch (Opcode) { + default: + return false; + case ARM::t2MOVCClsl: case ARM::t2MOVCClsr: + case ARM::t2MOVCCasr: case ARM::t2MOVCCror: + case ARM::t2LSLri: case ARM::t2LSRri: + case ARM::t2ASRri: case ARM::t2RORri: + return true; + } +} + +// A6.3.11 Data-processing (shifted register) +// +// Two register operands (Rn=0b1111 no 1st operand reg): Rs Rm +// Two register operands (Rs=0b1111 no dst operand reg): Rn Rm +// Three register operands: Rs Rn Rm +// Three register operands: (Rn=0b1111 Conditional Move) Rs Ro(TIED_TO) Rm +// +// Constant shifts t2_so_reg is a 2-operand unit corresponding to the Thumb2 +// register with shift forms: (Rm, ConstantShiftSpecifier). +// Constant shift specifier: Imm = (ShOp | ShAmt<<3). +// +// There are special instructions, like t2MOVsra_flag and t2MOVsrl_flag, which +// only require two register operands: Rd, Rm in ARM Reference Manual terms, and +// nothing else, because the shift amount is already specified. +// Similar case holds for t2MOVrx, t2ADDrr, ..., etc. +static bool DisassembleThumb2DPSoReg(MCInst &MI, unsigned Opcode, uint32_t insn, + unsigned short NumOps, unsigned &NumOpsAdded) { + + const TargetInstrDesc &TID = ARMInsts[Opcode]; + const TargetOperandInfo *OpInfo = TID.OpInfo; + unsigned &OpIdx = NumOpsAdded; + + // Special case handling. + if (Opcode == ARM::t2BR_JT) { + assert(NumOps == 4 + && OpInfo[0].RegClass == ARM::GPRRegClassID + && OpInfo[1].RegClass == ARM::GPRRegClassID + && OpInfo[2].RegClass == 0 + && OpInfo[3].RegClass == 0); + // Only need to populate the src reg operand. + MI.addOperand(MCOperand::CreateReg(getRegisterEnum(ARM::GPRRegClassID, + decodeRm(insn)))); + MI.addOperand(MCOperand::CreateReg(0)); + MI.addOperand(MCOperand::CreateImm(0)); + MI.addOperand(MCOperand::CreateImm(0)); + NumOpsAdded = 4; + return true; + } + + OpIdx = 0; + + assert(NumOps >= 2 + && OpInfo[0].RegClass == ARM::GPRRegClassID + && OpInfo[1].RegClass == ARM::GPRRegClassID); + + bool ThreeReg = (NumOps > 2 && OpInfo[2].RegClass == ARM::GPRRegClassID); + bool NoDstReg = (decodeRs(insn) == 0xF); + + // Build the register operands, followed by the constant shift specifier. + + MI.addOperand(MCOperand::CreateReg( + getRegisterEnum(ARM::GPRRegClassID, + NoDstReg ? decodeRn(insn) : decodeRs(insn)))); + ++OpIdx; + + if (ThreeReg) { + int Idx; + if ((Idx = TID.getOperandConstraint(OpIdx, TOI::TIED_TO)) != -1) { + // Process tied_to operand constraint. + MI.addOperand(MI.getOperand(Idx)); + } else { + assert(!NoDstReg); + MI.addOperand(MCOperand::CreateReg(getRegisterEnum(ARM::GPRRegClassID, + decodeRn(insn)))); + } + ++OpIdx; + } + + MI.addOperand(MCOperand::CreateReg(getRegisterEnum(ARM::GPRRegClassID, + decodeRm(insn)))); + ++OpIdx; + + if (NumOps == OpIdx) + return true; + + if (OpInfo[OpIdx].RegClass == 0 && !OpInfo[OpIdx].isPredicate() + && !OpInfo[OpIdx].isOptionalDef()) { + + if (Thumb2ShiftOpcode(Opcode)) + MI.addOperand(MCOperand::CreateImm(getShiftAmtBits(insn))); + else { + // Build the constant shift specifier operand. + unsigned bits2 = getShiftTypeBits(insn); + unsigned imm5 = getShiftAmtBits(insn); + ARM_AM::ShiftOpc ShOp = ARM_AM::no_shift; + unsigned ShAmt = decodeImmShift(bits2, imm5, ShOp); + + // PKHBT/PKHTB are special in that we need the decodeImmShift() call to + // decode the shift amount from raw imm5 and bits2, but we DO NOT need + // to encode the ShOp, as it's in the asm string already. + if (Opcode == ARM::t2PKHBT || Opcode == ARM::t2PKHTB) + MI.addOperand(MCOperand::CreateImm(ShAmt)); + else + MI.addOperand(MCOperand::CreateImm(ARM_AM::getSORegOpc(ShOp, ShAmt))); + } + ++OpIdx; + } + + return true; +} + +// A6.3.1 Data-processing (modified immediate) +// +// Two register operands: Rs Rn ModImm +// One register operands (Rs=0b1111 no explicit dest reg): Rn ModImm +// One register operands (Rn=0b1111 no explicit src reg): Rs ModImm - {t2MOVi, t2MVNi} +// +// ModImm = ThumbExpandImm(i:imm3:imm8) +static bool DisassembleThumb2DPModImm(MCInst &MI, unsigned Opcode, + uint32_t insn, unsigned short NumOps, unsigned &NumOpsAdded) { + + const TargetOperandInfo *OpInfo = ARMInsts[Opcode].OpInfo; + unsigned &OpIdx = NumOpsAdded; + + OpIdx = 0; + + assert(NumOps >= 2 && OpInfo[0].RegClass == ARM::GPRRegClassID); + + bool TwoReg = (OpInfo[1].RegClass == ARM::GPRRegClassID); + bool NoDstReg = (decodeRs(insn) == 0xF); + + // Build the register operands, followed by the modified immediate. + + MI.addOperand(MCOperand::CreateReg( + getRegisterEnum(ARM::GPRRegClassID, + NoDstReg ? decodeRn(insn) : decodeRs(insn)))); + ++OpIdx; + + if (TwoReg) { + assert(!NoDstReg); + MI.addOperand(MCOperand::CreateReg(getRegisterEnum(ARM::GPRRegClassID, + decodeRn(insn)))); + ++OpIdx; + } + + // The modified immediate operand should come next. + assert(OpIdx < NumOps && OpInfo[OpIdx].RegClass == 0 && + !OpInfo[OpIdx].isPredicate() && !OpInfo[OpIdx].isOptionalDef()); + + // i:imm3:imm8 + // A6.3.2 Modified immediate constants in Thumb instructions + unsigned imm12 = getIImm3Imm8(insn); + MI.addOperand(MCOperand::CreateImm(ThumbExpandImm(imm12))); + ++OpIdx; + + return true; +} + +static inline bool Thumb2SaturateOpcode(unsigned Opcode) { + switch (Opcode) { + case ARM::t2SSATlsl: case ARM::t2SSATasr: case ARM::t2SSAT16: + case ARM::t2USATlsl: case ARM::t2USATasr: case ARM::t2USAT16: + return true; + default: + return false; + } +} + +static inline unsigned decodeThumb2SaturatePos(unsigned Opcode, uint32_t insn) { + switch (Opcode) { + case ARM::t2SSATlsl: + case ARM::t2SSATasr: + return slice(insn, 4, 0) + 1; + case ARM::t2SSAT16: + return slice(insn, 3, 0) + 1; + case ARM::t2USATlsl: + case ARM::t2USATasr: + return slice(insn, 4, 0); + case ARM::t2USAT16: + return slice(insn, 3, 0); + default: + llvm_unreachable("Invalid opcode passed in"); + return 0; + } +} + +// A6.3.3 Data-processing (plain binary immediate) +// +// o t2ADDri12, t2SUBri12: Rs Rn imm12 +// o t2LEApcrel (ADR): Rs imm12 +// o t2BFC (BFC): Rs Ro(TIED_TO) bf_inv_mask_imm +// o t2BFI (BFI) (Currently not defined in LLVM as of Jan-07-2010) +// o t2MOVi16: Rs imm16 +// o t2MOVTi16: Rs imm16 +// o t2SBFX (SBFX): Rs Rn lsb width +// o t2UBFX (UBFX): Rs Rn lsb width +// o t2BFI (BFI): Rs Rn lsb width +// +// [Signed|Unsigned] Saturate [16] +// +// o t2SSAT[lsl|asr], t2USAT[lsl|asr]: Rs sat_pos Rn shamt +// o t2SSAT16, t2USAT16: Rs sat_pos Rn +static bool DisassembleThumb2DPBinImm(MCInst &MI, unsigned Opcode, + uint32_t insn, unsigned short NumOps, unsigned &NumOpsAdded) { + + const TargetInstrDesc &TID = ARMInsts[Opcode]; + const TargetOperandInfo *OpInfo = TID.OpInfo; + unsigned &OpIdx = NumOpsAdded; + + OpIdx = 0; + + assert(NumOps >= 2 && OpInfo[0].RegClass == ARM::GPRRegClassID); + + bool TwoReg = (OpInfo[1].RegClass == ARM::GPRRegClassID); + + // Build the register operand(s), followed by the immediate(s). + + MI.addOperand(MCOperand::CreateReg(getRegisterEnum(ARM::GPRRegClassID, + decodeRs(insn)))); + ++OpIdx; + + // t2SSAT/t2SSAT16/t2USAT/t2USAT16 has imm operand after Rd. + if (Thumb2SaturateOpcode(Opcode)) { + MI.addOperand(MCOperand::CreateImm(decodeThumb2SaturatePos(Opcode, insn))); + + MI.addOperand(MCOperand::CreateReg(getRegisterEnum(ARM::GPRRegClassID, + decodeRn(insn)))); + + if (Opcode == ARM::t2SSAT16 || Opcode == ARM::t2USAT16) { + OpIdx += 2; + return true; + } + + // For SSAT operand reg (Rn) has been disassembled above. + // Now disassemble the shift amount. + + // Inst{14-12:7-6} encodes the imm5 shift amount. + unsigned ShAmt = slice(insn, 14, 12) << 2 | slice(insn, 7, 6); + + MI.addOperand(MCOperand::CreateImm(ShAmt)); + + OpIdx += 3; + return true; + } + + if (TwoReg) { + assert(NumOps >= 3); + int Idx; + if ((Idx = TID.getOperandConstraint(OpIdx, TOI::TIED_TO)) != -1) { + // Process tied_to operand constraint. + MI.addOperand(MI.getOperand(Idx)); + } else { + // Add src reg operand. + MI.addOperand(MCOperand::CreateReg(getRegisterEnum(ARM::GPRRegClassID, + decodeRn(insn)))); + } + ++OpIdx; + } + + assert(OpInfo[OpIdx].RegClass == 0 && !OpInfo[OpIdx].isPredicate() + && !OpInfo[OpIdx].isOptionalDef()); + + // Pre-increment OpIdx. + ++OpIdx; + + if (Opcode == ARM::t2ADDri12 || Opcode == ARM::t2SUBri12 + || Opcode == ARM::t2LEApcrel) + MI.addOperand(MCOperand::CreateImm(getIImm3Imm8(insn))); + else if (Opcode == ARM::t2MOVi16 || Opcode == ARM::t2MOVTi16) + MI.addOperand(MCOperand::CreateImm(getImm16(insn))); + else if (Opcode == ARM::t2BFC) + MI.addOperand(MCOperand::CreateImm(getBitfieldInvMask(insn))); + else { + // Handle the case of: lsb width + assert(Opcode == ARM::t2SBFX || Opcode == ARM::t2UBFX || + Opcode == ARM::t2BFI); + MI.addOperand(MCOperand::CreateImm(getLsb(insn))); + if (Opcode == ARM::t2BFI) { + assert(getMsb(insn) >= getLsb(insn)); + MI.addOperand(MCOperand::CreateImm(getMsb(insn) - getLsb(insn) + 1)); + } else + MI.addOperand(MCOperand::CreateImm(getWidthMinus1(insn) + 1)); + + ++OpIdx; + } + + return true; +} + +// A6.3.4 Table A6-15 Miscellaneous control instructions +// A8.6.41 DMB +// A8.6.42 DSB +// A8.6.49 ISB +static inline bool t2MiscCtrlInstr(uint32_t insn) { + if (slice(insn, 31, 20) == 0xf3b && slice(insn, 15, 14) == 2 && + slice(insn, 12, 12) == 0) + return true; + + return false; +} + +// A6.3.4 Branches and miscellaneous control +// +// A8.6.16 B +// Branches: t2B, t2Bcc -> imm operand +// +// Branches: t2TPsoft -> no operand +// +// A8.6.23 BL, BLX (immediate) +// Branches (defined in ARMInstrThumb.td): tBLr9, tBLXi_r9 -> imm operand +// +// A8.6.26 +// t2BXJ -> Rn +// +// Miscellaneous control: t2Int_MemBarrierV7 (and its t2DMB variants), +// t2Int_SyncBarrierV7 (and its t2DSB varianst), t2ISBsy, t2CLREX +// -> no operand (except pred-imm pred-ccr for CLREX, memory barrier variants) +// +// Hint: t2NOP, t2YIELD, t2WFE, t2WFI, t2SEV +// -> no operand (except pred-imm pred-ccr) +// +// t2DBG -> imm4 = Inst{3-0} +// +// t2MRS/t2MRSsys -> Rs +// t2MSR/t2MSRsys -> Rn mask=Inst{11-8} +// t2SMC -> imm4 = Inst{19-16} +static bool DisassembleThumb2BrMiscCtrl(MCInst &MI, unsigned Opcode, + uint32_t insn, unsigned short NumOps, unsigned &NumOpsAdded) { + + if (NumOps == 0) + return true; + + if (t2MiscCtrlInstr(insn)) + return true; + + switch (Opcode) { + case ARM::t2CLREX: + case ARM::t2NOP: + case ARM::t2YIELD: + case ARM::t2WFE: + case ARM::t2WFI: + case ARM::t2SEV: + return true; + default: + break; + } + + // CPS has a singleton $opt operand that contains the following information: + // opt{4-0} = mode from Inst{4-0} + // opt{5} = changemode from Inst{8} + // opt{8-6} = AIF from Inst{7-5} + // opt{10-9} = imod from Inst{10-9} with 0b10 as enable and 0b11 as disable + if (Opcode == ARM::t2CPS) { + unsigned Option = slice(insn, 4, 0) | slice(insn, 8, 8) << 5 | + slice(insn, 7, 5) << 6 | slice(insn, 10, 9) << 9; + MI.addOperand(MCOperand::CreateImm(Option)); + NumOpsAdded = 1; + return true; + } + + // DBG has its option specified in Inst{3-0}. + if (Opcode == ARM::t2DBG) { + MI.addOperand(MCOperand::CreateImm(slice(insn, 3, 0))); + NumOpsAdded = 1; + return true; + } + + // MRS and MRSsys take one GPR reg Rs. + if (Opcode == ARM::t2MRS || Opcode == ARM::t2MRSsys) { + MI.addOperand(MCOperand::CreateReg(getRegisterEnum(ARM::GPRRegClassID, + decodeRs(insn)))); + NumOpsAdded = 1; + return true; + } + // BXJ takes one GPR reg Rn. + if (Opcode == ARM::t2BXJ) { + MI.addOperand(MCOperand::CreateReg(getRegisterEnum(ARM::GPRRegClassID, + decodeRn(insn)))); + NumOpsAdded = 1; + return true; + } + // MSR and MSRsys take one GPR reg Rn, followed by the mask. + if (Opcode == ARM::t2MSR || Opcode == ARM::t2MSRsys || Opcode == ARM::t2BXJ) { + MI.addOperand(MCOperand::CreateReg(getRegisterEnum(ARM::GPRRegClassID, + decodeRn(insn)))); + MI.addOperand(MCOperand::CreateImm(slice(insn, 11, 8))); + NumOpsAdded = 2; + return true; + } + // SMC take imm4. + if (Opcode == ARM::t2SMC) { + MI.addOperand(MCOperand::CreateImm(slice(insn, 19, 16))); + NumOpsAdded = 1; + return true; + } + + // Add the imm operand. + int Offset = 0; + + switch (Opcode) { + default: + assert(0 && "Unreachable code"); + case ARM::t2B: + Offset = decodeImm32_B_EncodingT4(insn); + break; + case ARM::t2Bcc: + Offset = decodeImm32_B_EncodingT3(insn); + break; + case ARM::tBLr9: + Offset = decodeImm32_BL(insn); + break; + case ARM::tBLXi_r9: + Offset = decodeImm32_BLX(insn); + break; + } + // When executing a Thumb instruction, PC reads as the address of the current + // instruction plus 4. The assembler subtracts 4 from the difference between + // the branch instruction and the target address, disassembler has to add 4 to + // to compensate. + MI.addOperand(MCOperand::CreateImm(Offset + 4)); + + NumOpsAdded = 1; + + return true; +} + +static inline bool Thumb2PreloadOpcode(unsigned Opcode) { + switch (Opcode) { + default: + return false; + case ARM::t2PLDi12: case ARM::t2PLDi8: case ARM::t2PLDpci: + case ARM::t2PLDr: case ARM::t2PLDs: + case ARM::t2PLDWi12: case ARM::t2PLDWi8: case ARM::t2PLDWpci: + case ARM::t2PLDWr: case ARM::t2PLDWs: + case ARM::t2PLIi12: case ARM::t2PLIi8: case ARM::t2PLIpci: + case ARM::t2PLIr: case ARM::t2PLIs: + return true; + } +} + +static bool DisassembleThumb2PreLoad(MCInst &MI, unsigned Opcode, uint32_t insn, + unsigned short NumOps, unsigned &NumOpsAdded) { + + // Preload Data/Instruction requires either 2 or 3 operands. + // t2PLDi12, t2PLDi8, t2PLDpci: Rn [+/-]imm12/imm8 + // t2PLDr: Rn Rm + // t2PLDs: Rn Rm imm2=Inst{5-4} + // Same pattern applies for t2PLDW* and t2PLI*. + + const TargetInstrDesc &TID = ARMInsts[Opcode]; + const TargetOperandInfo *OpInfo = TID.OpInfo; + unsigned &OpIdx = NumOpsAdded; + + OpIdx = 0; + + assert(NumOps >= 2 && + OpInfo[0].RegClass == ARM::GPRRegClassID); + + MI.addOperand(MCOperand::CreateReg(getRegisterEnum(ARM::GPRRegClassID, + decodeRn(insn)))); + ++OpIdx; + + if (OpInfo[OpIdx].RegClass == ARM::GPRRegClassID) { + MI.addOperand(MCOperand::CreateReg(getRegisterEnum(ARM::GPRRegClassID, + decodeRm(insn)))); + } else { + assert(OpInfo[OpIdx].RegClass == 0 && !OpInfo[OpIdx].isPredicate() + && !OpInfo[OpIdx].isOptionalDef()); + int Offset = 0; + if (Opcode == ARM::t2PLDpci || Opcode == ARM::t2PLDWpci || + Opcode == ARM::t2PLIpci) { + bool Negative = slice(insn, 23, 23) == 0; + unsigned Imm12 = getImm12(insn); + Offset = Negative ? -1 - Imm12 : 1 * Imm12; + } else if (Opcode == ARM::t2PLDi8 || Opcode == ARM::t2PLDWi8 || + Opcode == ARM::t2PLIi8) { + // A8.6.117 Encoding T2: add = FALSE + unsigned Imm8 = getImm8(insn); + Offset = -1 - Imm8; + } else // The i12 forms. See, for example, A8.6.117 Encoding T1. + Offset = decodeImm12(insn); + MI.addOperand(MCOperand::CreateImm(Offset)); + } + ++OpIdx; + + if (OpIdx < NumOps && OpInfo[OpIdx].RegClass == 0 && + !OpInfo[OpIdx].isPredicate() && !OpInfo[OpIdx].isOptionalDef()) { + // Fills in the shift amount for t2PLDs, t2PLDWs, t2PLIs. + MI.addOperand(MCOperand::CreateImm(slice(insn, 5, 4))); + ++OpIdx; + } + + return true; +} + +// A8.6.63 LDRB (literal) +// A8.6.79 LDRSB (literal) +// A8.6.75 LDRH (literal) +// A8.6.83 LDRSH (literal) +// A8.6.59 LDR (literal) +// +// These instrs calculate an address from the PC value and an immediate offset. +// Rd Rn=PC (+/-)imm12 (+ if Inst{23} == 0b1) +static bool DisassembleThumb2Ldpci(MCInst &MI, unsigned Opcode, + uint32_t insn, unsigned short NumOps, unsigned &NumOpsAdded) { + + const TargetOperandInfo *OpInfo = ARMInsts[Opcode].OpInfo; + + assert(NumOps >= 2 && + OpInfo[0].RegClass == ARM::GPRRegClassID && + OpInfo[1].RegClass == 0); + + // Build the register operand, followed by the (+/-)imm12 immediate. + + MI.addOperand(MCOperand::CreateReg(getRegisterEnum(ARM::GPRRegClassID, + decodeRd(insn)))); + + MI.addOperand(MCOperand::CreateImm(decodeImm12(insn))); + + NumOpsAdded = 2; + + return true; +} + +// A6.3.10 Store single data item +// A6.3.9 Load byte, memory hints +// A6.3.8 Load halfword, memory hints +// A6.3.7 Load word +// +// For example, +// +// t2LDRi12: Rd Rn (+)imm12 +// t2LDRi8: Rd Rn (+/-)imm8 (+ if Inst{9} == 0b1) +// t2LDRs: Rd Rn Rm ConstantShiftSpecifier (see also DisassembleThumb2DPSoReg) +// t2LDR_POST: Rd Rn Rn(TIED_TO) (+/-)imm8 (+ if Inst{9} == 0b1) +// t2LDR_PRE: Rd Rn Rn(TIED_TO) (+/-)imm8 (+ if Inst{9} == 0b1) +// +// t2STRi12: Rd Rn (+)imm12 +// t2STRi8: Rd Rn (+/-)imm8 (+ if Inst{9} == 0b1) +// t2STRs: Rd Rn Rm ConstantShiftSpecifier (see also DisassembleThumb2DPSoReg) +// t2STR_POST: Rn Rd Rn(TIED_TO) (+/-)imm8 (+ if Inst{9} == 0b1) +// t2STR_PRE: Rn Rd Rn(TIED_TO) (+/-)imm8 (+ if Inst{9} == 0b1) +// +// Note that for indexed modes, the Rn(TIED_TO) operand needs to be populated +// correctly, as LLVM AsmPrinter depends on it. For indexed stores, the first +// operand is Rn; for all the other instructions, Rd is the first operand. +// +// Delegates to DisassembleThumb2PreLoad() for preload data/instruction. +// Delegates to DisassembleThumb2Ldpci() for load * literal operations. +static bool DisassembleThumb2LdSt(bool Load, MCInst &MI, unsigned Opcode, + uint32_t insn, unsigned short NumOps, unsigned &NumOpsAdded) { + + unsigned Rn = decodeRn(insn); + + if (Thumb2PreloadOpcode(Opcode)) + return DisassembleThumb2PreLoad(MI, Opcode, insn, NumOps, NumOpsAdded); + + // See, for example, A6.3.7 Load word: Table A6-18 Load word. + if (Load && Rn == 15) + return DisassembleThumb2Ldpci(MI, Opcode, insn, NumOps, NumOpsAdded); + + const TargetInstrDesc &TID = ARMInsts[Opcode]; + const TargetOperandInfo *OpInfo = TID.OpInfo; + unsigned &OpIdx = NumOpsAdded; + + OpIdx = 0; + + assert(NumOps >= 3 && + OpInfo[0].RegClass == ARM::GPRRegClassID && + OpInfo[1].RegClass == ARM::GPRRegClassID); + + bool ThreeReg = (OpInfo[2].RegClass == ARM::GPRRegClassID); + bool TIED_TO = ThreeReg && TID.getOperandConstraint(2, TOI::TIED_TO) != -1; + bool Imm12 = !ThreeReg && slice(insn, 23, 23) == 1; // ARMInstrThumb2.td + + // Build the register operands, followed by the immediate. + unsigned R0, R1, R2 = 0; + unsigned Rd = decodeRd(insn); + int Imm = 0; + + if (!Load && TIED_TO) { + R0 = Rn; + R1 = Rd; + } else { + R0 = Rd; + R1 = Rn; + } + if (ThreeReg) { + if (TIED_TO) { + R2 = Rn; + Imm = decodeImm8(insn); + } else { + R2 = decodeRm(insn); + // See, for example, A8.6.64 LDRB (register). + // And ARMAsmPrinter::printT2AddrModeSoRegOperand(). + // LSL is the default shift opc, and LLVM does not expect it to be encoded + // as part of the immediate operand. + // Imm = ARM_AM::getSORegOpc(ARM_AM::lsl, slice(insn, 5, 4)); + Imm = slice(insn, 5, 4); + } + } else { + if (Imm12) + Imm = getImm12(insn); + else + Imm = decodeImm8(insn); + } + + MI.addOperand(MCOperand::CreateReg(getRegisterEnum(ARM::GPRRegClassID, R0))); + ++OpIdx; + MI.addOperand(MCOperand::CreateReg(getRegisterEnum(ARM::GPRRegClassID, R1))); + ++OpIdx; + + if (ThreeReg) { + MI.addOperand(MCOperand::CreateReg(getRegisterEnum(ARM::GPRRegClassID,R2))); + ++OpIdx; + } + + assert(OpInfo[OpIdx].RegClass == 0 && !OpInfo[OpIdx].isPredicate() + && !OpInfo[OpIdx].isOptionalDef()); + + MI.addOperand(MCOperand::CreateImm(Imm)); + ++OpIdx; + + return true; +} + +// A6.3.12 Data-processing (register) +// +// Two register operands [rotate]: Rs Rm [rotation(= (rotate:'000'))] +// Three register operands only: Rs Rn Rm +// Three register operands [rotate]: Rs Rn Rm [rotation(= (rotate:'000'))] +// +// Parallel addition and subtraction 32-bit Thumb instructions: Rs Rn Rm +// +// Miscellaneous operations: Rs [Rn] Rm +static bool DisassembleThumb2DPReg(MCInst &MI, unsigned Opcode, uint32_t insn, + unsigned short NumOps, unsigned &NumOpsAdded) { + + const TargetInstrDesc &TID = ARMInsts[Opcode]; + const TargetOperandInfo *OpInfo = TID.OpInfo; + unsigned &OpIdx = NumOpsAdded; + + OpIdx = 0; + + assert(NumOps >= 2 && + OpInfo[0].RegClass == ARM::GPRRegClassID && + OpInfo[1].RegClass == ARM::GPRRegClassID); + + // Build the register operands, followed by the optional rotation amount. + + bool ThreeReg = NumOps > 2 && OpInfo[2].RegClass == ARM::GPRRegClassID; + + MI.addOperand(MCOperand::CreateReg(getRegisterEnum(ARM::GPRRegClassID, + decodeRs(insn)))); + ++OpIdx; + + if (ThreeReg) { + MI.addOperand(MCOperand::CreateReg(getRegisterEnum(ARM::GPRRegClassID, + decodeRn(insn)))); + ++OpIdx; + } + + MI.addOperand(MCOperand::CreateReg(getRegisterEnum(ARM::GPRRegClassID, + decodeRm(insn)))); + ++OpIdx; + + if (OpIdx < NumOps && OpInfo[OpIdx].RegClass == 0 + && !OpInfo[OpIdx].isPredicate() && !OpInfo[OpIdx].isOptionalDef()) { + // Add the rotation amount immediate. + MI.addOperand(MCOperand::CreateImm(decodeRotate(insn))); + ++OpIdx; + } + + return true; +} + +// A6.3.16 Multiply, multiply accumulate, and absolute difference +// +// t2MLA, t2MLS, t2SMMLA, t2SMMLS: Rs Rn Rm Ra=Inst{15-12} +// t2MUL, t2SMMUL: Rs Rn Rm +// t2SMLA[BB|BT|TB|TT|WB|WT]: Rs Rn Rm Ra=Inst{15-12} +// t2SMUL[BB|BT|TB|TT|WB|WT]: Rs Rn Rm +// +// Dual halfword multiply: t2SMUAD[X], t2SMUSD[X], t2SMLAD[X], t2SMLSD[X]: +// Rs Rn Rm Ra=Inst{15-12} +// +// Unsigned Sum of Absolute Differences [and Accumulate] +// Rs Rn Rm [Ra=Inst{15-12}] +static bool DisassembleThumb2Mul(MCInst &MI, unsigned Opcode, uint32_t insn, + unsigned short NumOps, unsigned &NumOpsAdded) { + + const TargetOperandInfo *OpInfo = ARMInsts[Opcode].OpInfo; + + assert(NumOps >= 3 && + OpInfo[0].RegClass == ARM::GPRRegClassID && + OpInfo[1].RegClass == ARM::GPRRegClassID && + OpInfo[2].RegClass == ARM::GPRRegClassID); + + // Build the register operands. + + bool FourReg = NumOps > 3 && OpInfo[3].RegClass == ARM::GPRRegClassID; + + MI.addOperand(MCOperand::CreateReg(getRegisterEnum(ARM::GPRRegClassID, + decodeRs(insn)))); + + MI.addOperand(MCOperand::CreateReg(getRegisterEnum(ARM::GPRRegClassID, + decodeRn(insn)))); + + MI.addOperand(MCOperand::CreateReg(getRegisterEnum(ARM::GPRRegClassID, + decodeRm(insn)))); + + if (FourReg) + MI.addOperand(MCOperand::CreateReg(getRegisterEnum(ARM::GPRRegClassID, + decodeRd(insn)))); + + NumOpsAdded = FourReg ? 4 : 3; + + return true; +} + +// A6.3.17 Long multiply, long multiply accumulate, and divide +// +// t2SMULL, t2UMULL, t2SMLAL, t2UMLAL, t2UMAAL: RdLo RdHi Rn Rm +// where RdLo = Inst{15-12} and RdHi = Inst{11-8} +// +// Halfword multiple accumulate long: t2SMLAL: RdLo RdHi Rn Rm +// where RdLo = Inst{15-12} and RdHi = Inst{11-8} +// +// Dual halfword multiple: t2SMLALD[X], t2SMLSLD[X]: RdLo RdHi Rn Rm +// where RdLo = Inst{15-12} and RdHi = Inst{11-8} +// +// Signed/Unsigned divide: t2SDIV, t2UDIV: Rs Rn Rm +static bool DisassembleThumb2LongMul(MCInst &MI, unsigned Opcode, uint32_t insn, + unsigned short NumOps, unsigned &NumOpsAdded) { + + const TargetOperandInfo *OpInfo = ARMInsts[Opcode].OpInfo; + + assert(NumOps >= 3 && + OpInfo[0].RegClass == ARM::GPRRegClassID && + OpInfo[1].RegClass == ARM::GPRRegClassID && + OpInfo[2].RegClass == ARM::GPRRegClassID); + + bool FourReg = NumOps > 3 && OpInfo[3].RegClass == ARM::GPRRegClassID; + + // Build the register operands. + + if (FourReg) + MI.addOperand(MCOperand::CreateReg(getRegisterEnum(ARM::GPRRegClassID, + decodeRd(insn)))); + + MI.addOperand(MCOperand::CreateReg(getRegisterEnum(ARM::GPRRegClassID, + decodeRs(insn)))); + + MI.addOperand(MCOperand::CreateReg(getRegisterEnum(ARM::GPRRegClassID, + decodeRn(insn)))); + + MI.addOperand(MCOperand::CreateReg(getRegisterEnum(ARM::GPRRegClassID, + decodeRm(insn)))); + + if (FourReg) + NumOpsAdded = 4; + else + NumOpsAdded = 3; + + return true; +} + +// See A6.3 32-bit Thumb instruction encoding for instruction classes +// corresponding to (op1, op2, op). +// +// Table A6-9 32-bit Thumb instruction encoding +// op1 op2 op Instruction class, see +// --- ------- -- ------------------------------------------------------------ +// 01 00xx0xx - Load/store multiple on page A6-23 +// 00xx1xx - Load/store dual, load/store exclusive, table branch on page A6-24 +// 01xxxxx - Data-processing (shifted register) on page A6-31 +// 1xxxxxx - Coprocessor instructions on page A6-40 +// 10 x0xxxxx 0 Data-processing (modified immediate) on page A6-15 +// x1xxxxx 0 Data-processing (plain binary immediate) on page A6-19 +// - 1 Branches and miscellaneous control on page A6-20 +// 11 000xxx0 - Store single data item on page A6-30 +// 001xxx0 - Advanced SIMD element or structure load/store instructions on page A7-27 +// 00xx001 - Load byte, memory hints on page A6-28 +// 00xx011 - Load halfword, memory hints on page A6-26 +// 00xx101 - Load word on page A6-25 +// 00xx111 - UNDEFINED +// 010xxxx - Data-processing (register) on page A6-33 +// 0110xxx - Multiply, multiply accumulate, and absolute difference on page A6-38 +// 0111xxx - Long multiply, long multiply accumulate, and divide on page A6-39 +// 1xxxxxx - Coprocessor instructions on page A6-40 +// +static bool DisassembleThumb2(uint16_t op1, uint16_t op2, uint16_t op, + MCInst &MI, unsigned Opcode, uint32_t insn, + unsigned short NumOps, unsigned &NumOpsAdded) { + + switch (op1) { + case 1: + if (slice(op2, 6, 5) == 0) { + if (slice(op2, 2, 2) == 0) { + // Load/store multiple. + return DisassembleThumb2LdStMul(MI, Opcode, insn, NumOps, NumOpsAdded); + } + + // Load/store dual, load/store exclusive, table branch, otherwise. + assert(slice(op2, 2, 2) == 1); + if ((ARM::t2LDREX <= Opcode && Opcode <= ARM::t2LDREXH) || + (ARM::t2STREX <= Opcode && Opcode <= ARM::t2STREXH)) { + // Load/store exclusive. + return DisassembleThumb2LdStEx(MI, Opcode, insn, NumOps, NumOpsAdded); + } + if (Opcode == ARM::t2LDRDi8 || + Opcode == ARM::t2LDRD_PRE || Opcode == ARM::t2LDRD_POST || + Opcode == ARM::t2STRDi8 || + Opcode == ARM::t2STRD_PRE || Opcode == ARM::t2STRD_POST) { + // Load/store dual. + return DisassembleThumb2LdStDual(MI, Opcode, insn, NumOps, NumOpsAdded); + } + if (Opcode == ARM::t2TBBgen || Opcode == ARM::t2TBHgen) { + // Table branch. + return DisassembleThumb2TB(MI, Opcode, insn, NumOps, NumOpsAdded); + } + } else if (slice(op2, 6, 5) == 1) { + // Data-processing (shifted register). + return DisassembleThumb2DPSoReg(MI, Opcode, insn, NumOps, NumOpsAdded); + } + + // FIXME: A6.3.18 Coprocessor instructions + // But see ThumbDisassembler::getInstruction(). + + break; + case 2: + if (op == 0) { + if (slice(op2, 5, 5) == 0) { + // Data-processing (modified immediate) + return DisassembleThumb2DPModImm(MI, Opcode, insn, NumOps, NumOpsAdded); + } else { + // Data-processing (plain binary immediate) + return DisassembleThumb2DPBinImm(MI, Opcode, insn, NumOps, NumOpsAdded); + } + } else { + // Branches and miscellaneous control on page A6-20. + return DisassembleThumb2BrMiscCtrl(MI, Opcode, insn, NumOps, NumOpsAdded); + } + + break; + case 3: + switch (slice(op2, 6, 5)) { + case 0: + // Load/store instructions... + if (slice(op2, 0, 0) == 0) { + if (slice(op2, 4, 4) == 0) { + // Store single data item on page A6-30 + return DisassembleThumb2LdSt(false, MI,Opcode,insn,NumOps,NumOpsAdded); + } else { + // FIXME: Advanced SIMD element or structure load/store instructions. + // But see ThumbDisassembler::getInstruction(). + ; + } + } else { + // Table A6-9 32-bit Thumb instruction encoding: Load byte|halfword|word + return DisassembleThumb2LdSt(true, MI,Opcode,insn,NumOps,NumOpsAdded); + } + break; + case 1: + if (slice(op2, 4, 4) == 0) { + // A6.3.12 Data-processing (register) + return DisassembleThumb2DPReg(MI, Opcode, insn, NumOps, NumOpsAdded); + } else if (slice(op2, 3, 3) == 0) { + // A6.3.16 Multiply, multiply accumulate, and absolute difference + return DisassembleThumb2Mul(MI, Opcode, insn, NumOps, NumOpsAdded); + } else { + // A6.3.17 Long multiply, long multiply accumulate, and divide + return DisassembleThumb2LongMul(MI, Opcode, insn, NumOps, NumOpsAdded); + } + break; + default: + // FIXME: A6.3.18 Coprocessor instructions + // But see ThumbDisassembler::getInstruction(). + ; + break; + } + + break; + default: + assert(0 && "Encoding error for Thumb2 instruction!"); + break; + } + + return false; +} + +static bool DisassembleThumbFrm(MCInst &MI, unsigned Opcode, uint32_t insn, + unsigned short NumOps, unsigned &NumOpsAdded) { + + uint16_t HalfWord = slice(insn, 31, 16); + + if (HalfWord == 0) { + // A6.2 16-bit Thumb instruction encoding + // op = bits[15:10] + uint16_t op = slice(insn, 15, 10); + return DisassembleThumb1(op, MI, Opcode, insn, NumOps, NumOpsAdded); + } + + unsigned bits15_11 = slice(HalfWord, 15, 11); + + // A6.1 Thumb instruction set encoding + assert((bits15_11 == 0x1D || bits15_11 == 0x1E || bits15_11 == 0x1F) && + "Bits [15:11] of first halfword of a Thumb2 instruction out of range"); + + // A6.3 32-bit Thumb instruction encoding + + uint16_t op1 = slice(HalfWord, 12, 11); + uint16_t op2 = slice(HalfWord, 10, 4); + uint16_t op = slice(insn, 15, 15); + + return DisassembleThumb2(op1, op2, op, MI, Opcode, insn, NumOps, NumOpsAdded); +} Modified: llvm/trunk/lib/Target/ARM/Makefile URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Target/ARM/Makefile?rev=98637&r1=98636&r2=98637&view=diff ============================================================================== --- llvm/trunk/lib/Target/ARM/Makefile (original) +++ llvm/trunk/lib/Target/ARM/Makefile Tue Mar 16 11:36:54 2010 @@ -16,8 +16,9 @@ ARMGenRegisterInfo.inc ARMGenInstrNames.inc \ ARMGenInstrInfo.inc ARMGenAsmWriter.inc \ ARMGenDAGISel.inc ARMGenSubtarget.inc \ - ARMGenCodeEmitter.inc ARMGenCallingConv.inc + ARMGenCodeEmitter.inc ARMGenCallingConv.inc \ + ARMGenDisassemblerTables.inc -DIRS = AsmPrinter AsmParser TargetInfo +DIRS = AsmPrinter AsmParser Disassembler TargetInfo include $(LEVEL)/Makefile.common Modified: llvm/trunk/lib/Target/ARM/Thumb2ITBlockPass.cpp URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Target/ARM/Thumb2ITBlockPass.cpp?rev=98637&r1=98636&r2=98637&view=diff ============================================================================== --- llvm/trunk/lib/Target/ARM/Thumb2ITBlockPass.cpp (original) +++ llvm/trunk/lib/Target/ARM/Thumb2ITBlockPass.cpp Tue Mar 16 11:36:54 2010 @@ -78,14 +78,16 @@ DebugLoc ndl = NMI->getDebugLoc(); unsigned NPredReg = 0; ARMCC::CondCodes NCC = getPredicate(NMI, NPredReg); - if (NCC == OCC) { - Mask |= (1 << Pos); - } else if (NCC != CC) + if (NCC == CC || NCC == OCC) + Mask |= (NCC & 1) << Pos; + else break; --Pos; ++MBBI; } Mask |= (1 << Pos); + // Tag along (firstcond[0] << 4) with the mask. + Mask |= (CC & 1) << 4; MIB.addImm(Mask); Modified = true; ++NumITs; Modified: llvm/trunk/test/CodeGen/ARM/2009-10-27-double-align.ll URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/CodeGen/ARM/2009-10-27-double-align.ll?rev=98637&r1=98636&r2=98637&view=diff ============================================================================== --- llvm/trunk/test/CodeGen/ARM/2009-10-27-double-align.ll (original) +++ llvm/trunk/test/CodeGen/ARM/2009-10-27-double-align.ll Tue Mar 16 11:36:54 2010 @@ -4,8 +4,8 @@ define arm_aapcscc void @g() { entry: -;CHECK: [sp, #+8] -;CHECK: [sp, #+12] +;CHECK: [sp, #8] +;CHECK: [sp, #12] ;CHECK: [sp] tail call arm_aapcscc void (i8*, ...)* @f(i8* getelementptr ([1 x i8]* @.str, i32 0, i32 0), i32 1, double 2.000000e+00, i32 3, double 4.000000e+00) ret void Modified: llvm/trunk/test/CodeGen/ARM/2009-10-30.ll URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/CodeGen/ARM/2009-10-30.ll?rev=98637&r1=98636&r2=98637&view=diff ============================================================================== --- llvm/trunk/test/CodeGen/ARM/2009-10-30.ll (original) +++ llvm/trunk/test/CodeGen/ARM/2009-10-30.ll Tue Mar 16 11:36:54 2010 @@ -6,7 +6,7 @@ entry: ;CHECK: sub sp, sp, #4 ;CHECK: add r{{[0-9]+}}, sp, #8 -;CHECK: str r{{[0-9]+}}, [sp], #+4 +;CHECK: str r{{[0-9]+}}, [sp], #4 ;CHECK: bx lr %ap = alloca i8*, align 4 %ap1 = bitcast i8** %ap to i8* Modified: llvm/trunk/test/CodeGen/ARM/arm-negative-stride.ll URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/CodeGen/ARM/arm-negative-stride.ll?rev=98637&r1=98636&r2=98637&view=diff ============================================================================== --- llvm/trunk/test/CodeGen/ARM/arm-negative-stride.ll (original) +++ llvm/trunk/test/CodeGen/ARM/arm-negative-stride.ll Tue Mar 16 11:36:54 2010 @@ -5,7 +5,7 @@ define void @test(i32* %P, i32 %A, i32 %i) nounwind { entry: -; CHECK: str r1, [{{r.*}}, +{{r.*}}, lsl #2] +; CHECK: str r1, [{{r.*}}, {{r.*}}, lsl #2] icmp eq i32 %i, 0 ; :0 [#uses=1] br i1 %0, label %return, label %bb Modified: llvm/trunk/test/CodeGen/ARM/globals.ll URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/CodeGen/ARM/globals.ll?rev=98637&r1=98636&r2=98637&view=diff ============================================================================== --- llvm/trunk/test/CodeGen/ARM/globals.ll (original) +++ llvm/trunk/test/CodeGen/ARM/globals.ll Tue Mar 16 11:36:54 2010 @@ -41,7 +41,7 @@ ; DarwinPIC: _test1: ; DarwinPIC: ldr r0, LCPI1_0 ; DarwinPIC: LPC1_0: -; DarwinPIC: ldr r0, [pc, +r0] +; DarwinPIC: ldr r0, [pc, r0] ; DarwinPIC: ldr r0, [r0] ; DarwinPIC: bx lr @@ -63,7 +63,7 @@ ; LinuxPIC: .LPC1_0: ; LinuxPIC: add r0, pc, r0 -; LinuxPIC: ldr r0, [r1, +r0] +; LinuxPIC: ldr r0, [r1, r0] ; LinuxPIC: ldr r0, [r0] ; LinuxPIC: bx lr Modified: llvm/trunk/test/CodeGen/ARM/ldrd.ll URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/CodeGen/ARM/ldrd.ll?rev=98637&r1=98636&r2=98637&view=diff ============================================================================== --- llvm/trunk/test/CodeGen/ARM/ldrd.ll (original) +++ llvm/trunk/test/CodeGen/ARM/ldrd.ll Tue Mar 16 11:36:54 2010 @@ -10,10 +10,10 @@ ;V6: ldrd r2, [r2] ;V5: ldr r3, [r2] -;V5: ldr r2, [r2, #+4] +;V5: ldr r2, [r2, #4] ;EABI: ldr r3, [r2] -;EABI: ldr r2, [r2, #+4] +;EABI: ldr r2, [r2, #4] %0 = load i64** @b, align 4 %1 = load i64* %0, align 4 Modified: llvm/trunk/test/CodeGen/ARM/str_pre-2.ll URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/CodeGen/ARM/str_pre-2.ll?rev=98637&r1=98636&r2=98637&view=diff ============================================================================== --- llvm/trunk/test/CodeGen/ARM/str_pre-2.ll (original) +++ llvm/trunk/test/CodeGen/ARM/str_pre-2.ll Tue Mar 16 11:36:54 2010 @@ -1,5 +1,5 @@ ; RUN: llc < %s -mtriple=arm-linux-gnu | grep {str.*\\!} -; RUN: llc < %s -mtriple=arm-linux-gnu | grep {ldr.*\\\[.*\], #+4} +; RUN: llc < %s -mtriple=arm-linux-gnu | grep {ldr.*\\\[.*\], #4} @b = external global i64* Modified: llvm/trunk/test/CodeGen/ARM/tls2.ll URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/CodeGen/ARM/tls2.ll?rev=98637&r1=98636&r2=98637&view=diff ============================================================================== --- llvm/trunk/test/CodeGen/ARM/tls2.ll (original) +++ llvm/trunk/test/CodeGen/ARM/tls2.ll Tue Mar 16 11:36:54 2010 @@ -7,7 +7,7 @@ define i32 @f() { ; CHECK-NONPIC: f: -; CHECK-NONPIC: ldr {{r.}}, [pc, +{{r.}}] +; CHECK-NONPIC: ldr {{r.}}, [pc, {{r.}}] ; CHECK-NONPIC: i(gottpoff) ; CHECK-PIC: f: ; CHECK-PIC: __tls_get_addr @@ -18,7 +18,7 @@ define i32* @g() { ; CHECK-NONPIC: g: -; CHECK-NONPIC: ldr {{r.}}, [pc, +{{r.}}] +; CHECK-NONPIC: ldr {{r.}}, [pc, {{r.}}] ; CHECK-NONPIC: i(gottpoff) ; CHECK-PIC: g: ; CHECK-PIC: __tls_get_addr Modified: llvm/trunk/test/CodeGen/Thumb2/ldr-str-imm12.ll URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/CodeGen/Thumb2/ldr-str-imm12.ll?rev=98637&r1=98636&r2=98637&view=diff ============================================================================== --- llvm/trunk/test/CodeGen/Thumb2/ldr-str-imm12.ll (original) +++ llvm/trunk/test/CodeGen/Thumb2/ldr-str-imm12.ll Tue Mar 16 11:36:54 2010 @@ -22,7 +22,7 @@ define arm_apcscc %union.rec* @Manifest(%union.rec* %x, %union.rec* %env, %struct.STYLE* %style, %union.rec** %bthr, %union.rec** %fthr, %union.rec** %target, %union.rec** %crs, i32 %ok, i32 %need_expand, %union.rec** %enclose, i32 %fcr) nounwind { entry: -; CHECK: ldr.w r9, [r7, #+28] +; CHECK: ldr.w r9, [r7, #28] %xgaps.i = alloca [32 x %union.rec*], align 4 ; <[32 x %union.rec*]*> [#uses=0] %ycomp.i = alloca [32 x %union.rec*], align 4 ; <[32 x %union.rec*]*> [#uses=0] br i1 false, label %bb, label %bb20 @@ -50,9 +50,9 @@ bb420: ; preds = %bb20, %bb20 ; CHECK: bb420 ; CHECK: str r{{[0-7]}}, [sp] -; CHECK: str r{{[0-7]}}, [sp, #+4] -; CHECK: str r{{[0-7]}}, [sp, #+8] -; CHECK: str{{(.w)?}} r{{[0-9]+}}, [sp, #+24] +; CHECK: str r{{[0-7]}}, [sp, #4] +; CHECK: str r{{[0-7]}}, [sp, #8] +; CHECK: str{{(.w)?}} r{{[0-9]+}}, [sp, #24] store %union.rec* null, %union.rec** @zz_hold, align 4 store %union.rec* null, %union.rec** @zz_res, align 4 store %union.rec* %x, %union.rec** @zz_hold, align 4 Modified: llvm/trunk/test/CodeGen/Thumb2/thumb2-ldr.ll URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/CodeGen/Thumb2/thumb2-ldr.ll?rev=98637&r1=98636&r2=98637&view=diff ============================================================================== --- llvm/trunk/test/CodeGen/Thumb2/thumb2-ldr.ll (original) +++ llvm/trunk/test/CodeGen/Thumb2/thumb2-ldr.ll Tue Mar 16 11:36:54 2010 @@ -11,7 +11,7 @@ define i32 @f2(i32* %v) { entry: ; CHECK: f2: -; CHECK: ldr.w r0, [r0, #+4092] +; CHECK: ldr.w r0, [r0, #4092] %tmp2 = getelementptr i32* %v, i32 1023 %tmp = load i32* %tmp2 ret i32 %tmp Modified: llvm/trunk/test/CodeGen/Thumb2/thumb2-ldrh.ll URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/CodeGen/Thumb2/thumb2-ldrh.ll?rev=98637&r1=98636&r2=98637&view=diff ============================================================================== --- llvm/trunk/test/CodeGen/Thumb2/thumb2-ldrh.ll (original) +++ llvm/trunk/test/CodeGen/Thumb2/thumb2-ldrh.ll Tue Mar 16 11:36:54 2010 @@ -11,7 +11,7 @@ define i16 @f2(i16* %v) { entry: ; CHECK: f2: -; CHECK: ldrh.w r0, [r0, #+2046] +; CHECK: ldrh.w r0, [r0, #2046] %tmp2 = getelementptr i16* %v, i16 1023 %tmp = load i16* %tmp2 ret i16 %tmp Modified: llvm/trunk/test/CodeGen/Thumb2/thumb2-str.ll URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/CodeGen/Thumb2/thumb2-str.ll?rev=98637&r1=98636&r2=98637&view=diff ============================================================================== --- llvm/trunk/test/CodeGen/Thumb2/thumb2-str.ll (original) +++ llvm/trunk/test/CodeGen/Thumb2/thumb2-str.ll Tue Mar 16 11:36:54 2010 @@ -9,7 +9,7 @@ define i32 @f2(i32 %a, i32* %v) { ; CHECK: f2: -; CHECK: str.w r0, [r1, #+4092] +; CHECK: str.w r0, [r1, #4092] %tmp2 = getelementptr i32* %v, i32 1023 store i32 %a, i32* %tmp2 ret i32 %a Modified: llvm/trunk/test/CodeGen/Thumb2/thumb2-str_pre.ll URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/CodeGen/Thumb2/thumb2-str_pre.ll?rev=98637&r1=98636&r2=98637&view=diff ============================================================================== --- llvm/trunk/test/CodeGen/Thumb2/thumb2-str_pre.ll (original) +++ llvm/trunk/test/CodeGen/Thumb2/thumb2-str_pre.ll Tue Mar 16 11:36:54 2010 @@ -2,7 +2,7 @@ define void @test1(i32* %X, i32* %A, i32** %dest) { ; CHECK: test1 -; CHECK: str r1, [r0, #+16]! +; CHECK: str r1, [r0, #16]! %B = load i32* %A ; [#uses=1] %Y = getelementptr i32* %X, i32 4 ; [#uses=2] store i32 %B, i32* %Y @@ -12,7 +12,7 @@ define i16* @test2(i16* %X, i32* %A) { ; CHECK: test2 -; CHECK: strh r1, [r0, #+8]! +; CHECK: strh r1, [r0, #8]! %B = load i32* %A ; [#uses=1] %Y = getelementptr i16* %X, i32 4 ; [#uses=2] %tmp = trunc i32 %B to i16 ; [#uses=1] Modified: llvm/trunk/test/CodeGen/Thumb2/thumb2-strb.ll URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/CodeGen/Thumb2/thumb2-strb.ll?rev=98637&r1=98636&r2=98637&view=diff ============================================================================== --- llvm/trunk/test/CodeGen/Thumb2/thumb2-strb.ll (original) +++ llvm/trunk/test/CodeGen/Thumb2/thumb2-strb.ll Tue Mar 16 11:36:54 2010 @@ -9,7 +9,7 @@ define i8 @f2(i8 %a, i8* %v) { ; CHECK: f2: -; CHECK: strb.w r0, [r1, #+4092] +; CHECK: strb.w r0, [r1, #4092] %tmp2 = getelementptr i8* %v, i32 4092 store i8 %a, i8* %tmp2 ret i8 %a Modified: llvm/trunk/test/CodeGen/Thumb2/thumb2-strh.ll URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/CodeGen/Thumb2/thumb2-strh.ll?rev=98637&r1=98636&r2=98637&view=diff ============================================================================== --- llvm/trunk/test/CodeGen/Thumb2/thumb2-strh.ll (original) +++ llvm/trunk/test/CodeGen/Thumb2/thumb2-strh.ll Tue Mar 16 11:36:54 2010 @@ -9,7 +9,7 @@ define i16 @f2(i16 %a, i16* %v) { ; CHECK: f2: -; CHECK: strh.w r0, [r1, #+4092] +; CHECK: strh.w r0, [r1, #4092] %tmp2 = getelementptr i16* %v, i32 2046 store i16 %a, i16* %tmp2 ret i16 %a Modified: llvm/trunk/utils/TableGen/DisassemblerEmitter.cpp URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/utils/TableGen/DisassemblerEmitter.cpp?rev=98637&r1=98636&r2=98637&view=diff ============================================================================== --- llvm/trunk/utils/TableGen/DisassemblerEmitter.cpp (original) +++ llvm/trunk/utils/TableGen/DisassemblerEmitter.cpp Tue Mar 16 11:36:54 2010 @@ -12,6 +12,8 @@ #include "Record.h" #include "X86DisassemblerTables.h" #include "X86RecognizableInstr.h" +#include "RISCDisassemblerEmitter.h" + using namespace llvm; using namespace llvm::X86Disassembler; @@ -124,6 +126,12 @@ return; } + // Fixed-instruction-length targets use a common disassembler. + if (Target.getName() == "ARM") { + RISCDisassemblerEmitter(Records).run(OS); + return; + } + throw TGError(Target.getTargetRecord()->getLoc(), "Unable to generate disassembler for this target"); } Added: llvm/trunk/utils/TableGen/RISCDisassemblerEmitter.cpp URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/utils/TableGen/RISCDisassemblerEmitter.cpp?rev=98637&view=auto ============================================================================== --- llvm/trunk/utils/TableGen/RISCDisassemblerEmitter.cpp (added) +++ llvm/trunk/utils/TableGen/RISCDisassemblerEmitter.cpp Tue Mar 16 11:36:54 2010 @@ -0,0 +1,1743 @@ +//===- RISCDisassemblerEmitter.cpp - Disassembler Generator ---------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// FIXME: document +// +//===----------------------------------------------------------------------===// + +#define DEBUG_TYPE "risc-disassembler-emitter" + +#include "RISCDisassemblerEmitter.h" +#include "CodeGenTarget.h" +#include "Record.h" +#include "llvm/ADT/StringExtras.h" +#include "llvm/Support/Debug.h" +#include "llvm/Support/raw_ostream.h" + +#include +#include +#include +#include +#include +#include + +using namespace llvm; + +//////////////////////////////////// +// Utility classes / structures // +//////////////////////////////////// + +// LLVM coding style +#define INDENT_LEVEL 2 + +/// Indenter - A little helper class to keep track of the indentation depth, +/// while the instance object is being passed around. +class Indenter { +public: + Indenter() : depth(0) {} + + void push() { + depth += INDENT_LEVEL; + } + + void pop() { + if (depth >= INDENT_LEVEL) + depth -= INDENT_LEVEL; + } + + // Conversion operator. + operator int () { + return depth; + } +private: + uint8_t depth; +}; + +///////////////////////// +// Utility functions // +///////////////////////// + +static uint8_t byteFromBitsInit(BitsInit &init) { + int width = init.getNumBits(); + + assert(width <= 8 && "Field is too large for uint8_t!"); + + int index; + uint8_t mask = 0x01; + + uint8_t ret = 0; + + for (index = 0; index < width; index++) { + if (static_cast(init.getBit(index))->getValue()) + ret |= mask; + + mask <<= 1; + } + + return ret; +} + +static uint8_t getByteField(const Record &def, const char *str) { + BitsInit *bits = def.getValueAsBitsInit(str); + return byteFromBitsInit(*bits); +} + +static BitsInit &getBitsField(const Record &def, const char *str) { + BitsInit *bits = def.getValueAsBitsInit(str); + return *bits; +} + +/// sameStringExceptEndingChar - Return true if the two strings differ only in +/// the ending char. ("VST4q8a", "VST4q8b", 'a', 'b') as input returns true. +static +bool sameStringExceptEndingChar(const std::string &LHS, const std::string &RHS, + char lhc, char rhc) { + + if (LHS.length() > 1 && RHS.length() > 1 && LHS.length() == RHS.length()) { + unsigned length = LHS.length(); + return LHS.substr(0, length - 1) == RHS.substr(0, length - 1) + && LHS[length - 1] == lhc && RHS[length - 1] == rhc; + } + + return false; +} + +/// thumbInstruction - Determine whether we have a Thumb instruction. +/// See also ARMInstrFormats.td. +static bool thumbInstruction(uint8_t Form) { + return Form == 23; +} + +// The set (BIT_TRUE, BIT_FALSE, BIT_UNSET) represents a ternary logic system +// for a bit value. +// +// BIT_UNFILTERED is used as the init value for a filter position. It is used +// only for filter processings. +typedef enum { + BIT_TRUE, // '1' + BIT_FALSE, // '0' + BIT_UNSET, // '?' + BIT_UNFILTERED // unfiltered +} bit_value_t; + +static bit_value_t bitFromBits(BitsInit &bits, unsigned index) { + if (BitInit *bit = dynamic_cast(bits.getBit(index))) + return bit->getValue() ? BIT_TRUE : BIT_FALSE; + + // The bit is uninitialized. + return BIT_UNSET; +} + +static void dumpBits(raw_ostream &o, BitsInit &bits) { + unsigned index; + + for (index = bits.getNumBits(); index > 0; index--) { + switch (bitFromBits(bits, index - 1)) { + case BIT_TRUE: + o << "1"; + break; + case BIT_FALSE: + o << "0"; + break; + case BIT_UNSET: + o << "_"; + break; + default: + assert(0 && "unexpected return value from bitFromBits"); + } + } +} + +///////////// +// Enums // +///////////// + +#define ARM_FORMATS \ + ENTRY(ARM_FORMAT_PSEUDO, 0) \ + ENTRY(ARM_FORMAT_MULFRM, 1) \ + ENTRY(ARM_FORMAT_BRFRM, 2) \ + ENTRY(ARM_FORMAT_BRMISCFRM, 3) \ + ENTRY(ARM_FORMAT_DPFRM, 4) \ + ENTRY(ARM_FORMAT_DPSOREGFRM, 5) \ + ENTRY(ARM_FORMAT_LDFRM, 6) \ + ENTRY(ARM_FORMAT_STFRM, 7) \ + ENTRY(ARM_FORMAT_LDMISCFRM, 8) \ + ENTRY(ARM_FORMAT_STMISCFRM, 9) \ + ENTRY(ARM_FORMAT_LDSTMULFRM, 10) \ + ENTRY(ARM_FORMAT_ARITHMISCFRM, 11) \ + ENTRY(ARM_FORMAT_EXTFRM, 12) \ + ENTRY(ARM_FORMAT_VFPUNARYFRM, 13) \ + ENTRY(ARM_FORMAT_VFPBINARYFRM, 14) \ + ENTRY(ARM_FORMAT_VFPCONV1FRM, 15) \ + ENTRY(ARM_FORMAT_VFPCONV2FRM, 16) \ + ENTRY(ARM_FORMAT_VFPCONV3FRM, 17) \ + ENTRY(ARM_FORMAT_VFPCONV4FRM, 18) \ + ENTRY(ARM_FORMAT_VFPCONV5FRM, 19) \ + ENTRY(ARM_FORMAT_VFPLDSTFRM, 20) \ + ENTRY(ARM_FORMAT_VFPLDSTMULFRM, 21) \ + ENTRY(ARM_FORMAT_VFPMISCFRM, 22) \ + ENTRY(ARM_FORMAT_THUMBFRM, 23) \ + ENTRY(ARM_FORMAT_NEONFRM, 24) \ + ENTRY(ARM_FORMAT_NEONGETLNFRM, 25) \ + ENTRY(ARM_FORMAT_NEONSETLNFRM, 26) \ + ENTRY(ARM_FORMAT_NEONDUPFRM, 27) \ + ENTRY(ARM_FORMAT_LDSTEXFRM, 28) \ + ENTRY(ARM_FORMAT_MISCFRM, 29) \ + ENTRY(ARM_FORMAT_THUMBMISCFRM, 30) + +// ARM instruction format specifies the encoding used by the instruction. +#define ENTRY(n, v) n = v, +typedef enum { + ARM_FORMATS + ARM_FORMAT_NA +} ARMFormat; +#undef ENTRY + +// Converts enum to const char*. +static const char *stringForARMFormat(ARMFormat form) { +#define ENTRY(n, v) case n: return #n; + switch(form) { + ARM_FORMATS + case ARM_FORMAT_NA: + default: + return ""; + } +#undef ENTRY +} + +#define NS_FORMATS \ + ENTRY(NS_FORMAT_NONE, 0) \ + ENTRY(NS_FORMAT_VLDSTLane, 1) \ + ENTRY(NS_FORMAT_VLDSTLaneDbl, 2) \ + ENTRY(NS_FORMAT_VLDSTRQ, 3) \ + ENTRY(NS_FORMAT_NVdImm, 4) \ + ENTRY(NS_FORMAT_NVdVmImm, 5) \ + ENTRY(NS_FORMAT_NVdVmImmVCVT, 6) \ + ENTRY(NS_FORMAT_NVdVmImmVDupLane, 7) \ + ENTRY(NS_FORMAT_NVdVmImmVSHLL, 8) \ + ENTRY(NS_FORMAT_NVectorShuffle, 9) \ + ENTRY(NS_FORMAT_NVectorShift, 10) \ + ENTRY(NS_FORMAT_NVectorShift2, 11) \ + ENTRY(NS_FORMAT_NVdVnVmImm, 12) \ + ENTRY(NS_FORMAT_NVdVnVmImmVectorShift, 13) \ + ENTRY(NS_FORMAT_NVdVnVmImmVectorExtract, 14) \ + ENTRY(NS_FORMAT_NVdVnVmImmMulScalar, 15) \ + ENTRY(NS_FORMAT_VTBL, 16) + +// NEON instruction sub-format further classify the NEONFrm instruction. +#define ENTRY(n, v) n = v, +typedef enum { + NS_FORMATS + NS_FORMAT_NA +} NSFormat; +#undef ENTRY + +// Converts enum to const char*. +static const char *stringForNSFormat(NSFormat form) { +#define ENTRY(n, v) case n: return #n; + switch(form) { + NS_FORMATS + case NS_FORMAT_NA: + default: + return ""; + } +#undef ENTRY +} + +// Enums for the available target names. +typedef enum { + TARGET_ARM = 0, + TARGET_THUMB +} TARGET_NAME_t; + +class AbstractFilterChooser { +public: + static TARGET_NAME_t TargetName; + static void setTargetName(TARGET_NAME_t tn) { TargetName = tn; } + virtual ~AbstractFilterChooser() {} + virtual void emitTop(raw_ostream &o, Indenter &i) = 0; + virtual void emitBot(raw_ostream &o, Indenter &i) = 0; +}; + +// Define the symbol here. +TARGET_NAME_t AbstractFilterChooser::TargetName; + +template +class FilterChooser : public AbstractFilterChooser { +protected: + // Representation of the instruction to work on. + typedef bit_value_t insn_t[tBitWidth]; + + class Filter { + protected: + FilterChooser *Owner; // pointer without ownership + unsigned StartBit; // the starting bit position + unsigned NumBits; // number of bits to filter + bool Mixed; // a mixed region contains both set and unset bits + + // Map of well-known segment value to the set of uid's with that value. + std::map > FilteredInstructions; + + // Set of uid's with non-constant segment values. + std::vector VariableInstructions; + + // Map of well-known segment value to its delegate. + std::map FilterChooserMap; + + // Number of instructions which fall under FilteredInstructions category. + unsigned NumFiltered; + + // Keeps track of the last opcode in the filtered bucket. + unsigned LastOpcFiltered; + + // Number of instructions which fall under VariableInstructions category. + unsigned NumVariable; + + public: + unsigned getNumFiltered() { return NumFiltered; } + unsigned getNumVariable() { return NumVariable; } + unsigned getSingletonOpc() { + assert(NumFiltered == 1); + return LastOpcFiltered; + } + FilterChooser &getVariableFC() { + assert(NumFiltered == 1); + assert(FilterChooserMap.size() == 1); + return FilterChooserMap.find(-1)->second; + } + + Filter(const Filter &f) : + Owner(f.Owner), + StartBit(f.StartBit), + NumBits(f.NumBits), + Mixed(f.Mixed), + FilteredInstructions(f.FilteredInstructions), + VariableInstructions(f.VariableInstructions), + FilterChooserMap(f.FilterChooserMap), + NumFiltered(f.NumFiltered), + LastOpcFiltered(f.LastOpcFiltered), + NumVariable(f.NumVariable) { } + + Filter(FilterChooser &owner, unsigned startBit, unsigned numBits, + bool mixed) : + Owner(&owner), + StartBit(startBit), + NumBits(numBits), + Mixed(mixed) + { + assert(StartBit + NumBits - 1 < tBitWidth); + + NumFiltered = 0; + LastOpcFiltered = 0; + NumVariable = 0; + + for (unsigned i = 0, e = Owner->Opcodes.size(); i != e; ++i) { + insn_t Insn; + + // Populates the insn given the uid. + Owner->insnWithID(Insn, Owner->Opcodes[i]); + + uint64_t Field; + // Scans the segment for possibly well-specified encoding bits. + bool ok = Owner->fieldFromInsn(Field, Insn, StartBit, NumBits); + + if (ok) { + // The encoding bits are well-known. Lets add the uid of the + // instruction into the bucket keyed off the constant field value. + LastOpcFiltered = Owner->Opcodes[i]; + FilteredInstructions[Field].push_back(LastOpcFiltered); + ++NumFiltered; + } else { + // Some of the encoding bit(s) are unspecfied. This contributes to + // one additional member of "Variable" instructions. + VariableInstructions.push_back(Owner->Opcodes[i]); + ++NumVariable; + } + } + + assert((FilteredInstructions.size() + VariableInstructions.size() > 0) + && "Filter returns no instruction categories"); + } + + // Divides the decoding task into sub tasks and delegates them to the + // inferior FilterChooser's. + // + // A special case arises when there's only one entry in the filtered + // instructions. In order to unambiguously decode the singleton, we need to + // match the remaining undecoded encoding bits against the singleton. + void recurse() { + std::map >::const_iterator mapIterator; + + bit_value_t BitValueArray[tBitWidth]; + // Starts by inheriting our parent filter chooser's filter bit values. + memcpy(BitValueArray, Owner->FilterBitValues, sizeof(BitValueArray)); + + unsigned bitIndex; + + if (VariableInstructions.size()) { + // Conservatively marks each segment position as BIT_UNSET. + for (bitIndex = 0; bitIndex < NumBits; bitIndex++) + BitValueArray[StartBit + bitIndex] = BIT_UNSET; + + // Delegates to an inferior filter chooser for futher processing on this + // group of instructions whose segment values are variable. + FilterChooserMap.insert(std::pair( + (unsigned)-1, + FilterChooser(Owner->AllInstructions, + VariableInstructions, + BitValueArray, + *Owner) + )); + } + + // No need to recurse for a singleton filtered instruction. + // See also Filter::emit(). + if (getNumFiltered() == 1) { + //Owner->SingletonExists(LastOpcFiltered); + assert(FilterChooserMap.size() == 1); + return; + } + + // Otherwise, create sub choosers. + for (mapIterator = FilteredInstructions.begin(); + mapIterator != FilteredInstructions.end(); + mapIterator++) { + + // Marks all the segment positions with either BIT_TRUE or BIT_FALSE. + for (bitIndex = 0; bitIndex < NumBits; bitIndex++) { + if (mapIterator->first & (1 << bitIndex)) + BitValueArray[StartBit + bitIndex] = BIT_TRUE; + else + BitValueArray[StartBit + bitIndex] = BIT_FALSE; + } + + // Delegates to an inferior filter chooser for futher processing on this + // category of instructions. + FilterChooserMap.insert(std::pair( + mapIterator->first, + FilterChooser(Owner->AllInstructions, + mapIterator->second, + BitValueArray, + *Owner) + )); + } + } + + // Emit code to decode instructions given a segment or segments of bits. + void emit(raw_ostream &o, Indenter &i) { + o.indent(i) << "// Check Inst{"; + + if (NumBits > 1) + o << (StartBit + NumBits - 1) << '-'; + + o << StartBit << "} ...\n"; + + o.indent(i) << "switch (fieldFromInstruction(insn, " + << StartBit << ", " << NumBits << ")) {\n"; + + typename std::map::iterator filterIterator; + + bool DefaultCase = false; + for (filterIterator = FilterChooserMap.begin(); + filterIterator != FilterChooserMap.end(); + filterIterator++) { + + // Field value -1 implies a non-empty set of variable instructions. + // See also recurse(). + if (filterIterator->first == (unsigned)-1) { + DefaultCase = true; + + o.indent(i) << "default:\n"; + o.indent(i) << " break; // fallthrough\n"; + + // Closing curly brace for the switch statement. + // This is unconventional because we want the default processing to be + // performed for the fallthrough cases as well, i.e., when the "cases" + // did not prove a decoded instruction. + o.indent(i) << "}\n"; + + } else { + o.indent(i) << "case " << filterIterator->first << ":\n"; + } + + // We arrive at a category of instructions with the same segment value. + // Now delegate to the sub filter chooser for further decodings. + // The case may fallthrough, which happens if the remaining well-known + // encoding bits do not match exactly. + if (!DefaultCase) i.push(); + { + bool finished = filterIterator->second.emit(o, i); + // For top level default case, there's no need for a break statement. + if (Owner->isTopLevel() && DefaultCase) + break; + if (!finished) + o.indent(i) << "break;\n"; + } + if (!DefaultCase) i.pop(); + } + + // If there is no default case, we still need to supply a closing brace. + if (!DefaultCase) { + // Closing curly brace for the switch statement. + o.indent(i) << "}\n"; + } + } + + // Returns the number of fanout produced by the filter. More fanout implies + // the filter distinguishes more categories of instructions. + unsigned usefulness() const { + if (VariableInstructions.size()) + return FilteredInstructions.size(); + else + return FilteredInstructions.size() + 1; + } + }; // End of inner class Filter + + friend class Filter; + + // Vector of codegen instructions to choose our filter. + const std::vector &AllInstructions; + + // Vector of uid's for this filter chooser to work on. + const std::vector Opcodes; + + // Vector of candidate filters. + std::vector Filters; + + // Array of bit values passed down from our parent. + // Set to all BIT_UNFILTERED's for Parent == NULL. + bit_value_t FilterBitValues[tBitWidth]; + + // Links to the FilterChooser above us in the decoding tree. + FilterChooser *Parent; + + // Index of the best filter from Filters. + int BestIndex; + +public: + FilterChooser(const FilterChooser &FC) : + AbstractFilterChooser(), + AllInstructions(FC.AllInstructions), + Opcodes(FC.Opcodes), + Filters(FC.Filters), + Parent(FC.Parent), + BestIndex(FC.BestIndex) + { + memcpy(FilterBitValues, FC.FilterBitValues, sizeof(FilterBitValues)); + } + + FilterChooser(const std::vector &Insts, + const std::vector &IDs) : + AllInstructions(Insts), + Opcodes(IDs), + Filters(), + Parent(NULL), + BestIndex(-1) + { + for (unsigned i = 0; i < tBitWidth; ++i) + FilterBitValues[i] = BIT_UNFILTERED; + + doFilter(); + } + + FilterChooser(const std::vector &Insts, + const std::vector &IDs, + bit_value_t (&ParentFilterBitValues)[tBitWidth], + FilterChooser &parent) : + AllInstructions(Insts), + Opcodes(IDs), + Filters(), + Parent(&parent), + BestIndex(-1) + { + for (unsigned i = 0; i < tBitWidth; ++i) + FilterBitValues[i] = ParentFilterBitValues[i]; + + doFilter(); + } + + // The top level filter chooser has NULL as its parent. + bool isTopLevel() { return Parent == NULL; } + + // This provides an opportunity for target specific code emission. + void emitTopHook(raw_ostream &o, Indenter &i) { + if (TargetName == TARGET_ARM) { + // Emit code that references the ARMFormat data type. + o << "static const ARMFormat ARMFormats[] = {\n"; + for (unsigned i = 0, e = AllInstructions.size(); i != e; ++i) { + const Record &Def = *(AllInstructions[i]->TheDef); + const std::string &Name = Def.getName(); + if (Def.isSubClassOf("InstARM") || Def.isSubClassOf("InstThumb")) + o.indent(2) << + stringForARMFormat((ARMFormat)getByteField(Def, "Form")); + else + o << " ARM_FORMAT_NA"; + + o << ",\t// Inst #" << i << " = " << Name << '\n'; + } + o << " ARM_FORMAT_NA\t// Unreachable.\n"; + o << "};\n\n"; + + // And emit code that references the NSFormat data type. + // This is meaningful only for NEONFrm instructions. + o << "static const NSFormat NSFormats[] = {\n"; + for (unsigned i = 0, e = AllInstructions.size(); i != e; ++i) { + const Record &Def = *(AllInstructions[i]->TheDef); + const std::string &Name = Def.getName(); + if (Def.isSubClassOf("NeonI") || Def.isSubClassOf("NeonXI")) + o.indent(2) << + stringForNSFormat((NSFormat)getByteField(Def, "NSForm")); + else + o << " NS_FORMAT_NA"; + + o << ",\t// Inst #" << i << " = " << Name << '\n'; + } + o << " NS_FORMAT_NA\t// Unreachable.\n"; + o << "};\n\n"; + } + } + + // Emit the top level typedef and decodeInstruction() function. + void emitTop(raw_ostream &o, Indenter &i) { + + // Run the target specific emit hook. + emitTopHook(o, i); + + switch(tBitWidth) { + case 8: + o.indent(i) << "typedef uint8_t field_t;\n"; + break; + case 16: + o.indent(i) << "typedef uint16_t field_t;\n"; + break; + case 32: + o.indent(i) << "typedef uint32_t field_t;\n"; + break; + case 64: + o.indent(i) << "typedef uint64_t field_t;\n"; + break; + default: + assert(0 && "Unexpected instruction size!"); + } + + o << '\n'; + + o.indent(i) << "static field_t " << + "fieldFromInstruction(field_t insn, unsigned startBit, unsigned numBits)\n"; + + o.indent(i) << "{\n"; + i.push(); + { + o.indent(i) << "assert(startBit + numBits <= " << tBitWidth + << " && \"Instruction field out of bounds!\");\n"; + o << '\n'; + o.indent(i) << "field_t fieldMask;\n"; + o << '\n'; + o.indent(i) << "if (numBits == " << tBitWidth << ")\n"; + + i.push(); + { + o.indent(i) << "fieldMask = (field_t)-1;\n"; + } + i.pop(); + + o.indent(i) << "else\n"; + + i.push(); + { + o.indent(i) << "fieldMask = ((1 << numBits) - 1) << startBit;\n"; + } + i.pop(); + + o << '\n'; + o.indent(i) << "return (insn & fieldMask) >> startBit;\n"; + } + i.pop(); + o.indent(i) << "}\n"; + + o << '\n'; + + o.indent(i) << "static uint16_t decodeInstruction(field_t insn) {\n"; + + i.push(); + { + // Emits code to decode the instructions. + emit(o, i); + + o << '\n'; + o.indent(i) << "return 0;\n"; + } + i.pop(); + + o.indent(i) << "}\n"; + + o << '\n'; + + } + + // This provides an opportunity for target specific code emission after + // emitTop(). + void emitBot(raw_ostream &o, Indenter &i) { + if (TargetName == TARGET_THUMB) { + // Emit code that decodes the Thumb ISA. + o.indent(i) + << "static uint16_t decodeThumbInstruction(field_t insn) {\n"; + + i.push(); + { + // Emits code to decode the instructions. + emit(o, i); + + o << '\n'; + o.indent(i) << "return 0;\n"; + } + i.pop(); + + o.indent(i) << "}\n"; + } + } + +protected: + // Populates the insn given the uid. + void insnWithID(insn_t &Insn, unsigned Opcode) const { + assert(Opcode > 10); + BitsInit &Bits = getBitsField(*AllInstructions[Opcode]->TheDef, "Inst"); + + for (unsigned i = 0; i < tBitWidth; ++i) + Insn[i] = bitFromBits(Bits, i); + } + + // Returns the record name. + const std::string &nameWithID(unsigned Opcode) const { + return AllInstructions[Opcode]->TheDef->getName(); + } + + // Populates the field of the insn given the start position and the number of + // consecutive bits to scan for. + // + // Returns false if and on the first uninitialized bit value encountered. + // Returns true, otherwise. + const bool fieldFromInsn(uint64_t &Field, insn_t &Insn, unsigned StartBit, + unsigned NumBits) const { + Field = 0; + + for (unsigned i = 0; i < NumBits; ++i) { + if (Insn[StartBit + i] == BIT_UNSET) + return false; + + if (Insn[StartBit + i] == BIT_TRUE) + Field = Field | (1 << i); + } + + return true; + } + + void dumpFilterArray(raw_ostream &o, bit_value_t (&filter)[tBitWidth]) { + unsigned bitIndex; + + for (bitIndex = tBitWidth; bitIndex > 0; bitIndex--) { + switch (filter[bitIndex - 1]) { + case BIT_UNFILTERED: + o << "."; + break; + case BIT_UNSET: + o << "_"; + break; + case BIT_TRUE: + o << "1"; + break; + case BIT_FALSE: + o << "0"; + break; + } + } + } + + void dumpStack(raw_ostream &o, const char *prefix) { + FilterChooser *current = this; + + while (current) { + o << prefix; + + dumpFilterArray(o, current->FilterBitValues); + + o << '\n'; + + current = current->Parent; + } + } + + Filter &bestFilter() { + assert(BestIndex != -1 && "BestIndex not set"); + return Filters[BestIndex]; + } + + // States of our finite state machines. + typedef enum { + ATTR_NONE, + ATTR_FILTERED, + ATTR_ALL_SET, + ATTR_ALL_UNSET, + ATTR_MIXED + } bitAttr_t; + + // Called from Filter::recurse() when singleton exists. For debug purpose. + void SingletonExists(unsigned Opc) { + + insn_t Insn0; + insnWithID(Insn0, Opc); + + errs() << "Singleton exists: " << nameWithID(Opc) + << " with its decoding dominating "; + for (unsigned i = 0; i < Opcodes.size(); ++i) { + if (Opcodes[i] == Opc) continue; + errs() << nameWithID(Opcodes[i]) << ' '; + } + errs() << '\n'; + + dumpStack(errs(), "\t\t"); + for (unsigned i = 0; i < Opcodes.size(); i++) { + const std::string &Name = nameWithID(Opcodes[i]); + + errs() << '\t' << Name << " "; + dumpBits(errs(), + getBitsField(*AllInstructions[Opcodes[i]]->TheDef, "Inst")); + errs() << '\n'; + } + } + + bool ValueSet(bit_value_t V) { + return (V == BIT_TRUE || V == BIT_FALSE); + } + bool ValueNotSet(bit_value_t V) { + return (V == BIT_UNSET); + } + int Value(bit_value_t V) { + return ValueNotSet(V) ? -1 : (V == BIT_FALSE ? 0 : 1); + } + bool PositionFiltered(unsigned i) { + return ValueSet(FilterBitValues[i]); + } + + // Calculates the island(s) needed to decode the instruction. + unsigned getIslands(std::vector &StartBits, + std::vector &EndBits, + std::vector &FieldVals, insn_t &Insn) + { + unsigned Num, BitNo; + Num = BitNo = 0; + + uint64_t FieldVal = 0; + + // 0: Init + // 1: Water + // 2: Island + int State = 0; + int Val = -1; + + for (unsigned i = 0; i < tBitWidth; ++i) { + Val = Value(Insn[i]); + bool Filtered = PositionFiltered(i); + switch (State) { + default: + assert(0 && "Unreachable code!"); + break; + case 0: + case 1: + if (Filtered || Val == -1) + State = 1; // Still in Water + else { + State = 2; // Into the Island + BitNo = 0; + StartBits.push_back(i); + FieldVal = Val; + } + break; + case 2: + if (Filtered || Val == -1) { + State = 1; // Into the Water + EndBits.push_back(i - 1); + FieldVals.push_back(FieldVal); + ++Num; + } else { + State = 2; // Still in Island + ++BitNo; + FieldVal = FieldVal | Val << BitNo; + } + break; + } + } + // If we are still in Island after the loop, do some housekeeping. + if (State == 2) { + EndBits.push_back(tBitWidth - 1); + FieldVals.push_back(FieldVal); + ++Num; + } + + /* + printf("StartBits.size()=%u,EndBits.size()=%u,FieldVals.size()=%u,Num=%u\n", + (unsigned)StartBits.size(), (unsigned)EndBits.size(), + (unsigned)FieldVals.size(), Num); + */ + + assert(StartBits.size() == Num && EndBits.size() == Num && + FieldVals.size() == Num); + + return Num; + } + + bool LdStCopEncoding1(unsigned Opc) { + const std::string &Name = nameWithID(Opc); + if (Name == "LDC_OFFSET" || Name == "LDC_OPTION" || + Name == "LDC_POST" || Name == "LDC_PRE" || + Name == "LDCL_OFFSET" || Name == "LDCL_OPTION" || + Name == "LDCL_POST" || Name == "LDCL_PRE" || + Name == "STC_OFFSET" || Name == "STC_OPTION" || + Name == "STC_POST" || Name == "STC_PRE" || + Name == "STCL_OFFSET" || Name == "STCL_OPTION" || + Name == "STCL_POST" || Name == "STCL_PRE") + return true; + else + return false; + } + + // Emits code to decode the singleton. Return true if we have matched all the + // well-known bits. + bool emitSingletonDecoder(raw_ostream &o, Indenter &i, unsigned Opc) { + + std::vector StartBits; + std::vector EndBits; + std::vector FieldVals; + insn_t Insn; + insnWithID(Insn, Opc); + + if (TargetName == TARGET_ARM && LdStCopEncoding1(Opc)) { + o.indent(i); + // A8.6.51 & A8.6.188 + // If coproc = 0b101?, i.e, slice(insn, 11, 8) = 10 or 11, escape. + o << "if (fieldFromInstruction(insn, 9, 3) == 5) break; // fallthrough\n"; + } + + // Look for islands of undecoded bits of the singleton. + getIslands(StartBits, EndBits, FieldVals, Insn); + + unsigned Size = StartBits.size(); + unsigned I, NumBits; + + // If we have matched all the well-known bits, just issue a return. + if (Size == 0) { + o.indent(i) << "return " << Opc << "; // " << nameWithID(Opc) << '\n'; + return true; + } + + // Otherwise, there are more decodings to be done! + + // Emit code to match the island(s) for the singleton. + o.indent(i) << "// Check "; + + for (I = Size; I != 0; --I) { + o << "Inst{" << EndBits[I-1] << '-' << StartBits[I-1] << "} "; + if (I > 1) + o << "&& "; + else + o << "for singleton decoding...\n"; + } + + o.indent(i) << "if ("; + + for (I = Size; I != 0; --I) { + NumBits = EndBits[I-1] - StartBits[I-1] + 1; + o << "fieldFromInstruction(insn, " << StartBits[I-1] << ", " << NumBits + << ") == " << FieldVals[I-1]; + if (I > 1) + o << " && "; + else + o << ")\n"; + } + + o.indent(i) << " return " << Opc << "; // " << nameWithID(Opc) << '\n'; + + return false; + } + + // Emits code to decode the singleton, and then to decode the rest. + void emitSingletonDecoder(raw_ostream &o, Indenter &i, Filter & Best) { + + unsigned Opc = Best.getSingletonOpc(); + + emitSingletonDecoder(o, i, Opc); + + // Emit code for the rest. + o.indent(i) << "else\n"; + i.push(); + { + Best.getVariableFC().emit(o, i); + } + i.pop(); + } + + // Assign a single filter and run with it. + void runSingleFilter(FilterChooser &owner, unsigned startBit, unsigned numBit, + bool mixed) { + Filters.clear(); + Filter F(*this, startBit, numBit, true); + Filters.push_back(F); + BestIndex = 0; // Sole Filter instance to choose from. + bestFilter().recurse(); + } + + bool filterProcessor(bool AllowMixed, bool Greedy = true) { + Filters.clear(); + BestIndex = -1; + unsigned numInstructions = Opcodes.size(); + + assert(numInstructions && "Filter created with no instructions"); + + // No further filtering is necessary. + if (numInstructions == 1) + return true; + + // Heuristics. See also doFilter()'s "Heuristics" comment when num of + // instructions is 3. + if (AllowMixed && !Greedy) { + assert(numInstructions == 3); + + for (unsigned i = 0; i < Opcodes.size(); ++i) { + std::vector StartBits; + std::vector EndBits; + std::vector FieldVals; + insn_t Insn; + + insnWithID(Insn, Opcodes[i]); + + // Look for islands of undecoded bits of any instruction. + if (getIslands(StartBits, EndBits, FieldVals, Insn) > 0) { + // Found an instruction with island(s). Now just assign a filter. + runSingleFilter(*this, StartBits[0], EndBits[0] - StartBits[0] + 1, + true); + return true; + } + } + } + + unsigned bitIndex, insnIndex; + + // We maintain tBitWidth copies of the bitAttrs automaton. + // The automaton consumes the corresponding bit from each + // instruction. + // + // Input symbols: 0, 1, and _ (unset). + // States: NONE, FILTERED, ALL_SET, ALL_UNSET, and MIXED. + // Initial state: NONE. + // + // (NONE) ------- [01] -> (ALL_SET) + // (NONE) ------- _ ----> (ALL_UNSET) + // (ALL_SET) ---- [01] -> (ALL_SET) + // (ALL_SET) ---- _ ----> (MIXED) + // (ALL_UNSET) -- [01] -> (MIXED) + // (ALL_UNSET) -- _ ----> (ALL_UNSET) + // (MIXED) ------ . ----> (MIXED) + // (FILTERED)---- . ----> (FILTERED) + + bitAttr_t bitAttrs[tBitWidth]; + + // FILTERED bit positions provide no entropy and are not worthy of pursuing. + // Filter::recurse() set either BIT_TRUE or BIT_FALSE for each position. + for (bitIndex = 0; bitIndex < tBitWidth; ++bitIndex) + if (FilterBitValues[bitIndex] == BIT_TRUE || + FilterBitValues[bitIndex] == BIT_FALSE) + bitAttrs[bitIndex] = ATTR_FILTERED; + else + bitAttrs[bitIndex] = ATTR_NONE; + + for (insnIndex = 0; insnIndex < numInstructions; ++insnIndex) { + insn_t insn; + + insnWithID(insn, Opcodes[insnIndex]); + + for (bitIndex = 0; bitIndex < tBitWidth; ++bitIndex) { + switch (bitAttrs[bitIndex]) { + case ATTR_NONE: + if (insn[bitIndex] == BIT_UNSET) + bitAttrs[bitIndex] = ATTR_ALL_UNSET; + else + bitAttrs[bitIndex] = ATTR_ALL_SET; + break; + case ATTR_ALL_SET: + if (insn[bitIndex] == BIT_UNSET) + bitAttrs[bitIndex] = ATTR_MIXED; + break; + case ATTR_ALL_UNSET: + if (insn[bitIndex] != BIT_UNSET) + bitAttrs[bitIndex] = ATTR_MIXED; + break; + case ATTR_MIXED: + case ATTR_FILTERED: + break; + } + } + } + + // The regionAttr automaton consumes the bitAttrs automatons' state, + // lowest-to-highest. + // + // Input symbols: F(iltered), (all_)S(et), (all_)U(nset), M(ixed) + // States: NONE, ALL_SET, MIXED + // Initial state: NONE + // + // (NONE) ----- F --> (NONE) + // (NONE) ----- S --> (ALL_SET) ; and set region start + // (NONE) ----- U --> (NONE) + // (NONE) ----- M --> (MIXED) ; and set region start + // (ALL_SET) -- F --> (NONE) ; and report an ALL_SET region + // (ALL_SET) -- S --> (ALL_SET) + // (ALL_SET) -- U --> (NONE) ; and report an ALL_SET region + // (ALL_SET) -- M --> (MIXED) ; and report an ALL_SET region + // (MIXED) ---- F --> (NONE) ; and report a MIXED region + // (MIXED) ---- S --> (ALL_SET) ; and report a MIXED region + // (MIXED) ---- U --> (NONE) ; and report a MIXED region + // (MIXED) ---- M --> (MIXED) + + bitAttr_t regionAttr = ATTR_NONE; + unsigned startBit = 0; + + for (bitIndex = 0; bitIndex < tBitWidth; bitIndex++) { + bitAttr_t bitAttr = bitAttrs[bitIndex]; + + assert(bitAttr != ATTR_NONE && "Bit without attributes"); + +#define SET_START \ + startBit = bitIndex; + +#define REPORT_REGION \ + if (regionAttr == ATTR_MIXED && AllowMixed) \ + Filters.push_back(Filter(*this, startBit, bitIndex - startBit, true)); \ + else if (regionAttr == ATTR_ALL_SET && !AllowMixed) \ + Filters.push_back(Filter(*this, startBit, bitIndex - startBit, false)); + + switch (regionAttr) { + case ATTR_NONE: + switch (bitAttr) { + case ATTR_FILTERED: + break; + case ATTR_ALL_SET: + SET_START + regionAttr = ATTR_ALL_SET; + break; + case ATTR_ALL_UNSET: + break; + case ATTR_MIXED: + SET_START + regionAttr = ATTR_MIXED; + break; + default: + assert(0 && "Unexpected bitAttr!"); + } + break; + case ATTR_ALL_SET: + switch (bitAttr) { + case ATTR_FILTERED: + REPORT_REGION + regionAttr = ATTR_NONE; + break; + case ATTR_ALL_SET: + break; + case ATTR_ALL_UNSET: + REPORT_REGION + regionAttr = ATTR_NONE; + break; + case ATTR_MIXED: + REPORT_REGION + SET_START + regionAttr = ATTR_MIXED; + break; + default: + assert(0 && "Unexpected bitAttr!"); + } + break; + case ATTR_MIXED: + switch (bitAttr) { + case ATTR_FILTERED: + REPORT_REGION + SET_START + regionAttr = ATTR_NONE; + break; + case ATTR_ALL_SET: + REPORT_REGION + SET_START + regionAttr = ATTR_ALL_SET; + break; + case ATTR_ALL_UNSET: + REPORT_REGION + regionAttr = ATTR_NONE; + break; + case ATTR_MIXED: + break; + default: + assert(0 && "Unexpected bitAttr!"); + } + break; + case ATTR_ALL_UNSET: + assert(0 && "regionAttr state machine has no ATTR_UNSET state"); + case ATTR_FILTERED: + assert(0 && "regionAttr state machine has no ATTR_FILTERED state"); + } + } + + // At the end, if we're still in ALL_SET or MIXED states, report a region + + switch (regionAttr) { + case ATTR_NONE: + break; + case ATTR_FILTERED: + break; + case ATTR_ALL_SET: + REPORT_REGION + break; + case ATTR_ALL_UNSET: + break; + case ATTR_MIXED: + REPORT_REGION + break; + } + +#undef SET_START +#undef REPORT_REGION + + // We have finished with the filter processings. Now it's time to choose + // the best performing filter. + + BestIndex = 0; + bool AllUseless = true; + unsigned BestScore = 0; + + for (unsigned i = 0, e = Filters.size(); i != e; ++i) { + unsigned Usefulness = Filters[i].usefulness(); + + if (Usefulness) + AllUseless = false; + + if (Usefulness > BestScore) { + BestIndex = i; + BestScore = Usefulness; + } + } + + if (!AllUseless) { + bestFilter().recurse(); + } + + return !AllUseless; + } // end of filterProcessor(bool) + + // Decides on the best configuration of filter(s) to use in order to decode + // the instructions. A conflict of instructions may occur, in which case we + // dump the conflict set to the standard error. + void doFilter() { + unsigned Num = Opcodes.size(); + assert(Num && "FilterChooser created with no instructions"); + + // Heuristics: Use Inst{31-28} as the top level filter for ARM ISA. + if (TargetName == TARGET_ARM && Parent == NULL) { + runSingleFilter(*this, 28, 4, false); + return; + } + + if (filterProcessor(false)) + return; + + if (filterProcessor(true)) + return; + + // Heuristics to cope with conflict set {t2CMPrs, t2SUBSrr, t2SUBSrs} where + // no single instruction for the maximum ATTR_MIXED region Inst{14-4} has a + // well-known encoding pattern. In such case, we backtrack and scan for the + // the very first consecutive ATTR_ALL_SET region and assign a filter to it. + if (Num == 3 && filterProcessor(true, false)) + return; + + // If we come to here, the instruction decoding has failed. + // Print out the instructions in the conflict set... + + BestIndex = -1; + + DEBUG({ + errs() << "Conflict:\n"; + + dumpStack(errs(), "\t\t"); + + for (unsigned i = 0; i < Num; i++) { + const std::string &Name = nameWithID(Opcodes[i]); + + errs() << '\t' << Name << " "; + dumpBits(errs(), + getBitsField(*AllInstructions[Opcodes[i]]->TheDef, "Inst")); + errs() << '\n'; + } + }); + } + + // Emits code to decode our share of instructions. Returns true if the + // emitted code causes a return, which occurs if we know how to decode + // the instruction at this level or the instruction is not decodeable. + bool emit(raw_ostream &o, Indenter &i) { + if (Opcodes.size() == 1) { + // There is only one instruction in the set, which is great! + // Call emitSingletonDecoder() to see whether there are any remaining + // encodings bits. + return emitSingletonDecoder(o, i, Opcodes[0]); + + } else if (BestIndex == -1) { + if (TargetName == TARGET_ARM && Opcodes.size() == 2) { + // Resolve the known conflict sets: + // + // 1. source registers are identical => VMOVDneon; otherwise => VORRd + // 2. source registers are identical => VMOVQ; otherwise => VORRq + // 3. LDR, LDRcp => return LDR for now. + // FIXME: How can we distinguish between LDR and LDRcp? Do we need to? + // 4. VLD[234]LN*a/VST[234]LN*a vs. VLD[234]LN*b/VST[234]LN*b conflicts + // are resolved returning the 'a' versions of the instructions. Note + // that the difference between a/b is that the former is for double- + // spaced even registers while the latter is for double-spaced odd + // registers. This is for codegen instruction selection purpose. + // For disassembly, it does not matter. + const std::string &name1 = nameWithID(Opcodes[0]); + const std::string &name2 = nameWithID(Opcodes[1]); + if ((name1 == "VMOVDneon" && name2 == "VORRd") || + (name1 == "VMOVQ" && name2 == "VORRq")) { + // Inserting the opening curly brace for this case block. + i.pop(); + o.indent(i) << "{\n"; + i.push(); + + o.indent(i) << "field_t N = fieldFromInstruction(insn, 7, 1), " + << "M = fieldFromInstruction(insn, 5, 1);\n"; + o.indent(i) << "field_t Vn = fieldFromInstruction(insn, 16, 4), " + << "Vm = fieldFromInstruction(insn, 0, 4);\n"; + o.indent(i) << "return (N == M && Vn == Vm) ? " + << Opcodes[0] << " /* " << name1 << " */ : " + << Opcodes[1] << " /* " << name2 << " */ ;\n"; + + // Inserting the closing curly brace for this case block. + i.pop(); + o.indent(i) << "}\n"; + i.push(); + + return true; + } + if (name1 == "LDR" && name2 == "LDRcp") { + o.indent(i) << "return " << Opcodes[0] + << "; // Returning LDR for {LDR, LDRcp}\n"; + return true; + } + if (sameStringExceptEndingChar(name1, name2, 'a', 'b')) { + o.indent(i) << "return " << Opcodes[0] << "; // Returning " << name1 + << " for {" << name1 << ", " << name2 << "}\n"; + return true; + } + + // Otherwise, it does not belong to the known conflict sets. + } + // We don't know how to decode these instructions! Dump the conflict set! + o.indent(i) << "return 0;" << " // Conflict set: "; + for (int i = 0, N = Opcodes.size(); i < N; ++i) { + o << nameWithID(Opcodes[i]); + if (i < (N - 1)) + o << ", "; + else + o << '\n'; + } + return true; + } else { + // Choose the best filter to do the decodings! + Filter &Best = bestFilter(); + if (Best.getNumFiltered() == 1) + emitSingletonDecoder(o, i, Best); + else + bestFilter().emit(o, i); + return false; + } + } +}; + +/////////////// +// Backend // +/////////////// + +class RISCDisassemblerEmitter::RISCDEBackend { +public: + RISCDEBackend(RISCDisassemblerEmitter &frontend) : + NumberedInstructions(), + Opcodes(), + Frontend(frontend), + Target(), + AFC(NULL) + { + populateInstructions(); + + if (Target.getName() == "ARM") { + TargetName = TARGET_ARM; + } else { + errs() << "Target name " << Target.getName() << " not recognized\n"; + assert(0 && "Unknown target"); + } + } + + ~RISCDEBackend() { + if (AFC) { + delete AFC; + AFC = NULL; + } + } + + void getInstructionsByEnumValue(std::vector + &NumberedInstructions) { + // Dig down to the proper namespace. Code shamelessly stolen from + // InstrEnumEmitter.cpp + std::string Namespace; + CodeGenTarget::inst_iterator II, E; + + for (II = Target.inst_begin(), E = Target.inst_end(); II != E; ++II) + if (II->second.Namespace != "TargetInstrInfo") { + Namespace = II->second.Namespace; + break; + } + + assert(!Namespace.empty() && "No instructions defined."); + + Target.getInstructionsByEnumValue(NumberedInstructions); + } + + bool populateInstruction(const CodeGenInstruction &CGI, TARGET_NAME_t TN) { + const Record &Def = *CGI.TheDef; + const std::string &Name = Def.getName(); + uint8_t Form = getByteField(Def, "Form"); + BitsInit &Bits = getBitsField(Def, "Inst"); + + if (TN == TARGET_ARM) { + // FIXME: what about Int_MemBarrierV6 and Int_SyncBarrierV6? + if ((Name != "Int_MemBarrierV7" && Name != "Int_SyncBarrierV7") && + Form == ARM_FORMAT_PSEUDO) + return false; + if (thumbInstruction(Form)) + return false; + if (Name.find("CMPz") != std::string::npos /* || + Name.find("CMNz") != std::string::npos */) + return false; + + // Ignore pseudo instructions. + if (Name == "BXr9" || Name == "BMOVPCRX" || Name == "BMOVPCRXr9") + return false; + + // VLDRQ/VSTRQ can be hanlded with the more generic VLDMD/VSTMD. + if (Name == "VLDRQ" || Name == "VSTRQ") + return false; + + // + // The following special cases are for conflict resolutions. + // + + // RSCSri and RSCSrs set the 's' bit, but are not predicated. We are + // better off using the generic RSCri and RSCrs instructions. + if (Name == "RSCSri" || Name == "RSCSrs") return false; + + // MOVCCr, MOVCCs, MOVCCi, FCYPScc, FCYPDcc, FNEGScc, and FNEGDcc are used + // in the compiler to implement conditional moves. We can ignore them in + // favor of their more generic versions of instructions. + // See also SDNode *ARMDAGToDAGISel::Select(SDValue Op). + if (Name == "MOVCCr" || Name == "MOVCCs" || Name == "MOVCCi" || + Name == "FCPYScc" || Name == "FCPYDcc" || + Name == "FNEGScc" || Name == "FNEGDcc") + return false; + + // Ditto for VMOVDcc, VMOVScc, VNEGDcc, and VNEGScc. + if (Name == "VMOVDcc" || Name == "VMOVScc" || Name == "VNEGDcc" || + Name == "VNEGScc") + return false; + + // Ignore the *_sfp instructions when decoding. They are used by the + // compiler to implement scalar floating point operations using vector + // operations in order to work around some performance issues. + if (Name.find("_sfp") != std::string::npos) return false; + + // LLVM added LDM/STM_UPD which conflicts with LDM/STM. + // Ditto for VLDMS_UPD, VLDMD_UPD, VSTMS_UPD, VSTMD_UPD. + if (Name == "LDM_UPD" || Name == "STM_UPD" || Name == "VLDMS_UPD" || + Name == "VLDMD_UPD" || Name == "VSTMS_UPD" || Name == "VSTMD_UPD") + return false; + + // LDM_RET is a special case of LDM (Load Multiple) where the registers + // loaded include the PC, causing a branch to a loaded address. Ignore + // the LDM_RET instruction when decoding. + if (Name == "LDM_RET") return false; + + // Bcc is in a more generic form than B. Ignore B when decoding. + if (Name == "B") return false; + + // Ignore the non-Darwin BL instructions and the TPsoft (TLS) instruction. + if (Name == "BL" || Name == "BL_pred" || Name == "BLX" || Name == "BX" || + Name == "TPsoft") + return false; + + // Ignore VDUPf[d|q] instructions known to conflict with VDUP32[d-q] for + // decoding. The instruction duplicates an element from an ARM core + // register into every element of the destination vector. There is no + // distinction between data types. + if (Name == "VDUPfd" || Name == "VDUPfq") return false; + + // A8-598: VEXT + // Vector Extract extracts elements from the bottom end of the second + // operand vector and the top end of the first, concatenates them and + // places the result in the destination vector. The elements of the + // vectors are treated as being 8-bit bitfields. There is no distinction + // between data types. The size of the operation can be specified in + // assembler as vext.size. If the value is 16, 32, or 64, the syntax is + // a pseudo-instruction for a VEXT instruction specifying the equivalent + // number of bytes. + // + // Variants VEXTd16, VEXTd32, VEXTd8, and VEXTdf are reduced to VEXTd8; + // variants VEXTq16, VEXTq32, VEXTq8, and VEXTqf are reduced to VEXTq8. + if (Name == "VEXTd16" || Name == "VEXTd32" || Name == "VEXTdf" || + Name == "VEXTq16" || Name == "VEXTq32" || Name == "VEXTqf") + return false; + + // Vector Reverse is similar to Vector Extract. There is no distinction + // between data types, other than size. + // + // VREV64df is equivalent to VREV64d32. + // VREV64qf is equivalent to VREV64q32. + if (Name == "VREV64df" || Name == "VREV64qf") return false; + + // VDUPLNfd is equivalent to VDUPLN32d; VDUPfdf is specialized VDUPLN32d. + // VDUPLNfq is equivalent to VDUPLN32q; VDUPfqf is specialized VDUPLN32q. + // VLD1df is equivalent to VLD1d32. + // VLD1qf is equivalent to VLD1q32. + // VLD2d64 is equivalent to VLD1q64. + // VST1df is equivalent to VST1d32. + // VST1qf is equivalent to VST1q32. + // VST2d64 is equivalent to VST1q64. + if (Name == "VDUPLNfd" || Name == "VDUPfdf" || + Name == "VDUPLNfq" || Name == "VDUPfqf" || + Name == "VLD1df" || Name == "VLD1qf" || Name == "VLD2d64" || + Name == "VST1df" || Name == "VST1qf" || Name == "VST2d64") + return false; + } else if (TN == TARGET_THUMB) { + if (!thumbInstruction(Form)) + return false; + + // Ignore pseudo instructions. + if (Name == "tInt_eh_sjlj_setjmp" || Name == "t2Int_eh_sjlj_setjmp" || + Name == "t2MOVi32imm" || Name == "tBX" || Name == "tBXr9") + return false; + + // LLVM added tLDM_UPD which conflicts with tLDM. + if (Name == "tLDM_UPD") + return false; + + // On Darwin R9 is call-clobbered. Ignore the non-Darwin counterparts. + if (Name == "tBL" || Name == "tBLXi" || Name == "tBLXr") + return false; + + // Ignore the TPsoft (TLS) instructions, which conflict with tBLr9. + if (Name == "tTPsoft" || Name == "t2TPsoft") + return false; + + // Ignore tLEApcrel and tLEApcrelJT, prefer tADDrPCi. + if (Name == "tLEApcrel" || Name == "tLEApcrelJT") + return false; + + // Ignore t2LEApcrel, prefer the generic t2ADD* for disassembly printing. + if (Name == "t2LEApcrel") + return false; + + // Ignore tADDrSP, tADDspr, and tPICADD, prefer the generic tADDhirr. + // Ignore t2SUBrSPs, prefer the t2SUB[S]r[r|s]. + // Ignore t2ADDrSPs, prefer the t2ADD[S]r[r|s]. + if (Name == "tADDrSP" || Name == "tADDspr" || Name == "tPICADD" || + Name == "t2SUBrSPs" || Name == "t2ADDrSPs") + return false; + + // Ignore t2LDRDpci, prefer the generic t2LDRDi8, t2LDRD_PRE, t2LDRD_POST. + if (Name == "t2LDRDpci") + return false; + + // Ignore t2TBB, t2TBH and prefer the generic t2TBBgen, t2TBHgen. + if (Name == "t2TBB" || Name == "t2TBH") + return false; + + // Resolve conflicts: + // + // tBfar conflicts with tBLr9 + // tCMNz conflicts with tCMN (with assembly format strings being equal) + // tPOP_RET/t2LDM_RET conflict with tPOP/t2LDM (ditto) + // tMOVCCi conflicts with tMOVi8 + // tMOVCCr conflicts with tMOVgpr2gpr + // tBR_JTr conflicts with tBRIND + // tSpill conflicts with tSTRspi + // tLDRcp conflicts with tLDRspi + // tRestore conflicts with tLDRspi + // t2LEApcrelJT conflicts with t2LEApcrel + // t2ADDrSPi/t2SUBrSPi have more generic couterparts + if (Name == "tBfar" || + /* Name == "tCMNz" || */ Name == "tCMPzi8" || Name == "tCMPzr" || + Name == "tCMPzhir" || /* Name == "t2CMNzrr" || Name == "t2CMNzrs" || + Name == "t2CMNzri" || */ Name == "t2CMPzrr" || Name == "t2CMPzrs" || + Name == "t2CMPzri" || Name == "tPOP_RET" || Name == "t2LDM_RET" || + Name == "tMOVCCi" || Name == "tMOVCCr" || Name == "tBR_JTr" || + Name == "tSpill" || Name == "tLDRcp" || Name == "tRestore" || + Name == "t2LEApcrelJT" || Name == "t2ADDrSPi" || Name == "t2SUBrSPi") + return false; + } + + // Dumps the instruction encoding format. + switch (TargetName) { + case TARGET_ARM: + case TARGET_THUMB: + DEBUG(errs() << Name << " " << stringForARMFormat((ARMFormat)Form)); + break; + } + + DEBUG({ + errs() << " "; + + // Dumps the instruction encoding bits. + dumpBits(errs(), Bits); + + errs() << '\n'; + + // Dumps the list of operand info. + for (unsigned i = 0, e = CGI.OperandList.size(); i != e; ++i) { + CodeGenInstruction::OperandInfo Info = CGI.OperandList[i]; + const std::string &OperandName = Info.Name; + const Record &OperandDef = *Info.Rec; + + errs() << "\t" << OperandName << " (" << OperandDef.getName() << ")\n"; + } + }); + + return true; + } + + void populateInstructions() { + getInstructionsByEnumValue(NumberedInstructions); + + uint16_t numUIDs = NumberedInstructions.size(); + uint16_t uid; + + const char *instClass = NULL; + + switch (TargetName) { + case TARGET_ARM: + instClass = "InstARM"; + break; + default: + assert(0 && "Unreachable code!"); + } + + for (uid = 0; uid < numUIDs; uid++) { + // filter out intrinsics + if (!NumberedInstructions[uid]->TheDef->isSubClassOf(instClass)) + continue; + + if (populateInstruction(*NumberedInstructions[uid], TargetName)) + Opcodes.push_back(uid); + } + + // Special handling for the ARM chip, which supports two modes of execution. + // This branch handles the Thumb opcodes. + if (TargetName == TARGET_ARM) { + for (uid = 0; uid < numUIDs; uid++) { + // filter out intrinsics + if (!NumberedInstructions[uid]->TheDef->isSubClassOf("InstARM") + && !NumberedInstructions[uid]->TheDef->isSubClassOf("InstThumb")) + continue; + + if (populateInstruction(*NumberedInstructions[uid], TARGET_THUMB)) + Opcodes2.push_back(uid); + } + } + } + + // Emits disassembler code for instruction decoding. This delegates to the + // FilterChooser instance to do the heavy lifting. + void emit(raw_ostream &o) { + Indenter i; + std::string s; + raw_string_ostream ro(s); + + switch (TargetName) { + case TARGET_ARM: + Frontend.EmitSourceFileHeader("ARM Disassembler", ro); + break; + default: + assert(0 && "Unreachable code!"); + } + + ro.flush(); + o << s; + + o.indent(i) << "#include \n"; + o.indent(i) << "#include \n"; + o << '\n'; + o << "namespace llvm {\n\n"; + + AbstractFilterChooser::setTargetName(TargetName); + + switch (TargetName) { + case TARGET_ARM: { + // Emit common utility and ARM ISA decoder. + AFC = new FilterChooser<32>(NumberedInstructions, Opcodes); + AFC->emitTop(o, i); + delete AFC; + + // Emit Thumb ISA decoder as well. + AbstractFilterChooser::setTargetName(TARGET_THUMB); + AFC = new FilterChooser<32>(NumberedInstructions, Opcodes2); + AFC->emitBot(o, i); + break; + } + default: + assert(0 && "Unreachable code!"); + } + + o << "\n} // End llvm namespace \n"; + } + +protected: + std::vector NumberedInstructions; + std::vector Opcodes; + // Special case for the ARM chip, which supports ARM and Thumb ISAs. + // Opcodes2 will be populated with the Thumb opcodes. + std::vector Opcodes2; + RISCDisassemblerEmitter &Frontend; + CodeGenTarget Target; + AbstractFilterChooser *AFC; + + TARGET_NAME_t TargetName; +}; + +///////////////////////// +// Backend interface // +///////////////////////// + +void RISCDisassemblerEmitter::initBackend() +{ + Backend = new RISCDEBackend(*this); +} + +void RISCDisassemblerEmitter::run(raw_ostream &o) +{ + Backend->emit(o); +} + +void RISCDisassemblerEmitter::shutdownBackend() +{ + delete Backend; + Backend = NULL; +} Added: llvm/trunk/utils/TableGen/RISCDisassemblerEmitter.h URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/utils/TableGen/RISCDisassemblerEmitter.h?rev=98637&view=auto ============================================================================== --- llvm/trunk/utils/TableGen/RISCDisassemblerEmitter.h (added) +++ llvm/trunk/utils/TableGen/RISCDisassemblerEmitter.h Tue Mar 16 11:36:54 2010 @@ -0,0 +1,48 @@ +//===- RISCDisassemblerEmitter.h - Disassembler Generator -------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// FIXME: document +// +//===----------------------------------------------------------------------===// + +#ifndef RISCDISASSEMBLEREMITTER_H +#define RISCDISASSEMBLEREMITTER_H + +#include "TableGenBackend.h" + +#include + +namespace llvm { + +class RISCDisassemblerEmitter : public TableGenBackend { + RecordKeeper &Records; +public: + RISCDisassemblerEmitter(RecordKeeper &R) : Records(R) { + initBackend(); + } + + ~RISCDisassemblerEmitter() { + shutdownBackend(); + } + + // run - Output the code emitter + void run(raw_ostream &o); + +private: + class RISCDEBackend; + + RISCDEBackend *Backend; + + void initBackend(); + void shutdownBackend(); +}; + +} // end llvm namespace + +#endif Modified: llvm/trunk/utils/TableGen/TableGen.cpp URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/utils/TableGen/TableGen.cpp?rev=98637&r1=98636&r2=98637&view=diff ============================================================================== --- llvm/trunk/utils/TableGen/TableGen.cpp (original) +++ llvm/trunk/utils/TableGen/TableGen.cpp Tue Mar 16 11:36:54 2010 @@ -31,6 +31,7 @@ #include "OptParserEmitter.h" #include "Record.h" #include "RegisterInfoEmitter.h" +#include "RISCDisassemblerEmitter.h" #include "SubtargetEmitter.h" #include "TGParser.h" #include "llvm/Support/CommandLine.h" @@ -48,6 +49,7 @@ GenEmitter, GenRegisterEnums, GenRegister, GenRegisterHeader, GenInstrEnums, GenInstrs, GenAsmWriter, GenAsmMatcher, + GenRISCDisassembler, GenDisassembler, GenCallingConv, GenClangDiagsDefs, @@ -84,6 +86,9 @@ "Generate calling convention descriptions"), clEnumValN(GenAsmWriter, "gen-asm-writer", "Generate assembly writer"), + clEnumValN(GenRISCDisassembler, "gen-risc-disassembler", + "Generate disassembler for fixed instruction" + " length"), clEnumValN(GenDisassembler, "gen-disassembler", "Generate disassembler"), clEnumValN(GenAsmMatcher, "gen-asm-matcher", @@ -229,6 +234,9 @@ case GenAsmWriter: AsmWriterEmitter(Records).run(*Out); break; + case GenRISCDisassembler: + RISCDisassemblerEmitter(Records).run(*Out); + break; case GenAsmMatcher: AsmMatcherEmitter(Records).run(*Out); break; From anton at korobeynikov.info Tue Mar 16 11:45:43 2010 From: anton at korobeynikov.info (Anton Korobeynikov) Date: Tue, 16 Mar 2010 19:45:43 +0300 Subject: [llvm-commits] [llvm] r98637 - in /llvm/trunk: ./ lib/Target/ARM/ lib/Target/ARM/AsmPrinter/ lib/Target/ARM/Disassembler/ test/CodeGen/ARM/ test/CodeGen/Thumb2/ utils/TableGen/ In-Reply-To: <20100316163655.029872A6C12C@llvm.org> References: <20100316163655.029872A6C12C@llvm.org> Message-ID: Hi, Johny > Initial ARM/Thumb disassembler check-in. ?It consists of a tablgen backend > (RISCDisassemblerEmitter) which emits the decoder functions for ARM and Thumb, > and the disassembler core which invokes the decoder function and builds up the > MCInst based on the decoded Opcode. Quick q: here RISC means "completely fixed length"? Or, say, the instructions might be 16/32/24 bits length (contain 1/2 optional address fields)? -- With best regards, Anton Korobeynikov Faculty of Mathematics and Mechanics, Saint Petersburg State University From johnny.chen at apple.com Tue Mar 16 11:51:07 2010 From: johnny.chen at apple.com (Johnny Chen) Date: Tue, 16 Mar 2010 09:51:07 -0700 Subject: [llvm-commits] [llvm] r98637 - in /llvm/trunk: ./ lib/Target/ARM/ lib/Target/ARM/AsmPrinter/ lib/Target/ARM/Disassembler/ test/CodeGen/ARM/ test/CodeGen/Thumb2/ utils/TableGen/ In-Reply-To: References: <20100316163655.029872A6C12C@llvm.org> Message-ID: Fixed length. I treated Thumb/Thumb2 instructions as "fixed" length in this regard, zeroing the the top two bytes. It is easier for me to generate the decoder function for Thumb/Thumb2 this way. Thanks. On Mar 16, 2010, at 9:45 AM, Anton Korobeynikov wrote: > Hi, Johny > >> Initial ARM/Thumb disassembler check-in. It consists of a tablgen backend >> (RISCDisassemblerEmitter) which emits the decoder functions for ARM and Thumb, >> and the disassembler core which invokes the decoder function and builds up the >> MCInst based on the decoded Opcode. > Quick q: here RISC means "completely fixed length"? Or, say, the > instructions might be 16/32/24 bits length (contain 1/2 optional > address fields)? > > -- > With best regards, Anton Korobeynikov > Faculty of Mathematics and Mechanics, Saint Petersburg State University From bob.wilson at apple.com Tue Mar 16 11:59:47 2010 From: bob.wilson at apple.com (Bob Wilson) Date: Tue, 16 Mar 2010 16:59:47 -0000 Subject: [llvm-commits] [llvm] r98640 - in /llvm/trunk: ./ lib/Target/ARM/ lib/Target/ARM/AsmPrinter/ lib/Target/ARM/Disassembler/ test/CodeGen/ARM/ test/CodeGen/Thumb2/ utils/TableGen/ Message-ID: <20100316165947.E8BF82A6C12C@llvm.org> Author: bwilson Date: Tue Mar 16 11:59:47 2010 New Revision: 98640 URL: http://llvm.org/viewvc/llvm-project?rev=98640&view=rev Log: --- Reverse-merging r98637 into '.': U test/CodeGen/ARM/tls2.ll U test/CodeGen/ARM/arm-negative-stride.ll U test/CodeGen/ARM/2009-10-30.ll U test/CodeGen/ARM/globals.ll U test/CodeGen/ARM/str_pre-2.ll U test/CodeGen/ARM/ldrd.ll U test/CodeGen/ARM/2009-10-27-double-align.ll U test/CodeGen/Thumb2/thumb2-strb.ll U test/CodeGen/Thumb2/ldr-str-imm12.ll U test/CodeGen/Thumb2/thumb2-strh.ll U test/CodeGen/Thumb2/thumb2-ldr.ll U test/CodeGen/Thumb2/thumb2-str_pre.ll U test/CodeGen/Thumb2/thumb2-str.ll U test/CodeGen/Thumb2/thumb2-ldrh.ll U utils/TableGen/TableGen.cpp U utils/TableGen/DisassemblerEmitter.cpp D utils/TableGen/RISCDisassemblerEmitter.h D utils/TableGen/RISCDisassemblerEmitter.cpp U Makefile.rules U lib/Target/ARM/ARMInstrNEON.td U lib/Target/ARM/Makefile U lib/Target/ARM/AsmPrinter/ARMInstPrinter.cpp U lib/Target/ARM/AsmPrinter/ARMAsmPrinter.cpp U lib/Target/ARM/AsmPrinter/ARMInstPrinter.h D lib/Target/ARM/Disassembler U lib/Target/ARM/ARMInstrFormats.td U lib/Target/ARM/ARMAddressingModes.h U lib/Target/ARM/Thumb2ITBlockPass.cpp Removed: llvm/trunk/lib/Target/ARM/Disassembler/ llvm/trunk/utils/TableGen/RISCDisassemblerEmitter.cpp llvm/trunk/utils/TableGen/RISCDisassemblerEmitter.h Modified: llvm/trunk/Makefile.rules llvm/trunk/lib/Target/ARM/ARMAddressingModes.h llvm/trunk/lib/Target/ARM/ARMInstrFormats.td llvm/trunk/lib/Target/ARM/ARMInstrNEON.td llvm/trunk/lib/Target/ARM/AsmPrinter/ARMAsmPrinter.cpp llvm/trunk/lib/Target/ARM/AsmPrinter/ARMInstPrinter.cpp llvm/trunk/lib/Target/ARM/AsmPrinter/ARMInstPrinter.h llvm/trunk/lib/Target/ARM/Makefile llvm/trunk/lib/Target/ARM/Thumb2ITBlockPass.cpp llvm/trunk/test/CodeGen/ARM/2009-10-27-double-align.ll llvm/trunk/test/CodeGen/ARM/2009-10-30.ll llvm/trunk/test/CodeGen/ARM/arm-negative-stride.ll llvm/trunk/test/CodeGen/ARM/globals.ll llvm/trunk/test/CodeGen/ARM/ldrd.ll llvm/trunk/test/CodeGen/ARM/str_pre-2.ll llvm/trunk/test/CodeGen/ARM/tls2.ll llvm/trunk/test/CodeGen/Thumb2/ldr-str-imm12.ll llvm/trunk/test/CodeGen/Thumb2/thumb2-ldr.ll llvm/trunk/test/CodeGen/Thumb2/thumb2-ldrh.ll llvm/trunk/test/CodeGen/Thumb2/thumb2-str.ll llvm/trunk/test/CodeGen/Thumb2/thumb2-str_pre.ll llvm/trunk/test/CodeGen/Thumb2/thumb2-strb.ll llvm/trunk/test/CodeGen/Thumb2/thumb2-strh.ll llvm/trunk/utils/TableGen/DisassemblerEmitter.cpp llvm/trunk/utils/TableGen/TableGen.cpp Modified: llvm/trunk/Makefile.rules URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/Makefile.rules?rev=98640&r1=98639&r2=98640&view=diff ============================================================================== --- llvm/trunk/Makefile.rules (original) +++ llvm/trunk/Makefile.rules Tue Mar 16 11:59:47 2010 @@ -1614,11 +1614,6 @@ $(Echo) "Building $(> 8) * 2; } - /// getSOImmValOneRotate - Try to handle Imm with an immediate shifter - /// operand, computing the rotate amount to use. If this immediate value - /// cannot be handled with a single shifter-op, return 0. - static inline unsigned getSOImmValOneRotate(unsigned Imm) { - // A5.2.4 Constants with multiple encodings - // The lowest unsigned value of rotation wins! - for (unsigned R = 1; R <= 15; ++R) - if ((Imm & rotr32(~255U, 2*R)) == 0) - return 2*R; - - // Failed to find a suitable rotate amount. - return 0; - } - /// getSOImmValRotate - Try to handle Imm with an immediate shifter operand, /// computing the rotate amount to use. If this immediate value cannot be /// handled with a single shifter-op, determine a good rotate amount that will @@ -197,7 +179,7 @@ // of zero. if ((Arg & ~255U) == 0) return Arg; - unsigned RotAmt = getSOImmValOneRotate(Arg); + unsigned RotAmt = getSOImmValRotate(Arg); // If this cannot be handled with a single shifter_op, bail out. if (rotr32(~255U, RotAmt) & Arg) Modified: llvm/trunk/lib/Target/ARM/ARMInstrFormats.td URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Target/ARM/ARMInstrFormats.td?rev=98640&r1=98639&r2=98640&view=diff ============================================================================== --- llvm/trunk/lib/Target/ARM/ARMInstrFormats.td (original) +++ llvm/trunk/lib/Target/ARM/ARMInstrFormats.td Tue Mar 16 11:59:47 2010 @@ -1464,29 +1464,6 @@ // ARM NEON Instruction templates. // -// NSFormat specifies further details of a NEON instruction. This is used by -// the disassembler to classify NEONFrm instructions for disassembly purpose. -class NSFormat val> { - bits<5> Value = val; -} -def NSFormatNone : NSFormat<0>; -def VLDSTLaneFrm : NSFormat<1>; -def VLDSTLaneDblFrm : NSFormat<2>; -def VLDSTRQFrm : NSFormat<3>; -def NVdImmFrm : NSFormat<4>; -def NVdVmImmFrm : NSFormat<5>; -def NVdVmImmVCVTFrm : NSFormat<6>; -def NVdVmImmVDupLaneFrm : NSFormat<7>; -def NVdVmImmVSHLLFrm : NSFormat<8>; -def NVectorShuffleFrm : NSFormat<9>; -def NVectorShiftFrm : NSFormat<10>; -def NVectorShift2Frm : NSFormat<11>; -def NVdVnVmImmFrm : NSFormat<12>; -def NVdVnVmImmVectorShiftFrm : NSFormat<13>; -def NVdVnVmImmVectorExtractFrm : NSFormat<14>; -def NVdVnVmImmMulScalarFrm : NSFormat<15>; -def VTBLFrm : NSFormat<16>; - class NeonI pattern> : InstARM { @@ -1497,8 +1474,6 @@ !strconcat("\t", asm)); let Pattern = pattern; list Predicates = [HasNEON]; - NSFormat NSF = NSFormatNone; // For disassembly. - bits<5> NSForm = NSFormatNone.Value; // For disassembly. } // Same as NeonI except it does not have a "data type" specifier. @@ -1510,8 +1485,6 @@ let AsmString = !strconcat(!strconcat(opc, "${p}"), !strconcat("\t", asm)); let Pattern = pattern; list Predicates = [HasNEON]; - NSFormat NSF = NSFormatNone; // For disassembly. - bits<5> NSForm = NSFormatNone.Value; // For disassembly. } class NI pattern> : NeonXI { - let NSF = VLDSTRQFrm; // For disassembly. - let NSForm = VLDSTRQFrm.Value; // For disassembly. } class NLdSt op21_20, bits<4> op11_8, bits<4> op7_4, @@ -1538,8 +1509,6 @@ let Inst{21-20} = op21_20; let Inst{11-8} = op11_8; let Inst{7-4} = op7_4; - let NSF = VLDSTLaneFrm; // For disassembly. - let NSForm = VLDSTLaneFrm.Value; // For disassembly. } class NDataI op7_4, string OpcodeStr, string Dt> : NLdSt<0,0b10,0b1001,op7_4, (outs DPR:$dst1, DPR:$dst2), (ins addrmode6:$addr), IIC_VLD2, - OpcodeStr, Dt, "\\{$dst1, $dst2\\}, $addr", "", []> { - let NSF = VLDSTLaneDblFrm; // For disassembly. - let NSForm = VLDSTLaneDblFrm.Value; // For disassembly. -} + OpcodeStr, Dt, "\\{$dst1, $dst2\\}, $addr", "", []>; def VLD2d8D : VLD2Ddbl<0b0000, "vld2", "8">; def VLD2d16D : VLD2Ddbl<0b0100, "vld2", "16">; @@ -231,10 +228,7 @@ : NLdSt<0,0b10,0b0101,op7_4, (outs DPR:$dst1, DPR:$dst2, DPR:$dst3, GPR:$wb), (ins addrmode6:$addr), IIC_VLD3, OpcodeStr, Dt, "\\{$dst1, $dst2, $dst3\\}, $addr", - "$addr.addr = $wb", []> { - let NSF = VLDSTLaneDblFrm; // For disassembly. - let NSForm = VLDSTLaneDblFrm.Value; // For disassembly. -} + "$addr.addr = $wb", []>; def VLD3d8 : VLD3D<0b0000, "vld3", "8">; def VLD3d16 : VLD3D<0b0100, "vld3", "16">; @@ -266,10 +260,7 @@ (outs DPR:$dst1, DPR:$dst2, DPR:$dst3, DPR:$dst4, GPR:$wb), (ins addrmode6:$addr), IIC_VLD4, OpcodeStr, Dt, "\\{$dst1, $dst2, $dst3, $dst4\\}, $addr", - "$addr.addr = $wb", []> { - let NSF = VLDSTLaneDblFrm; // For disassembly. - let NSForm = VLDSTLaneDblFrm.Value; // For disassembly. -} + "$addr.addr = $wb", []>; def VLD4d8 : VLD4D<0b0000, "vld4", "8">; def VLD4d16 : VLD4D<0b0100, "vld4", "16">; @@ -306,28 +297,12 @@ def VLD2LNd32 : VLD2LN<0b1001, "vld2", "32"> { let Inst{6} = 0; } // vld2 to double-spaced even registers. -def VLD2LNq16a: VLD2LN<0b0101, "vld2", "16"> { - let Inst{5} = 1; - let NSF = VLDSTLaneDblFrm; // For disassembly. - let NSForm = VLDSTLaneDblFrm.Value; // For disassembly. -} -def VLD2LNq32a: VLD2LN<0b1001, "vld2", "32"> { - let Inst{6} = 1; - let NSF = VLDSTLaneDblFrm; // For disassembly. - let NSForm = VLDSTLaneDblFrm.Value; // For disassembly. -} +def VLD2LNq16a: VLD2LN<0b0101, "vld2", "16"> { let Inst{5} = 1; } +def VLD2LNq32a: VLD2LN<0b1001, "vld2", "32"> { let Inst{6} = 1; } // vld2 to double-spaced odd registers. -def VLD2LNq16b: VLD2LN<0b0101, "vld2", "16"> { - let Inst{5} = 1; - let NSF = VLDSTLaneDblFrm; // For disassembly. - let NSForm = VLDSTLaneDblFrm.Value; // For disassembly. -} -def VLD2LNq32b: VLD2LN<0b1001, "vld2", "32"> { - let Inst{6} = 1; - let NSF = VLDSTLaneDblFrm; // For disassembly. - let NSForm = VLDSTLaneDblFrm.Value; // For disassembly. -} +def VLD2LNq16b: VLD2LN<0b0101, "vld2", "16"> { let Inst{5} = 1; } +def VLD2LNq32b: VLD2LN<0b1001, "vld2", "32"> { let Inst{6} = 1; } // VLD3LN : Vector Load (single 3-element structure to one lane) class VLD3LN op11_8, string OpcodeStr, string Dt> @@ -343,11 +318,7 @@ def VLD3LNd32 : VLD3LN<0b1010, "vld3", "32"> { let Inst{6-4} = 0b000; } // vld3 to double-spaced even registers. -def VLD3LNq16a: VLD3LN<0b0110, "vld3", "16"> { - let Inst{5-4} = 0b10; - let NSF = VLDSTLaneDblFrm; // For disassembly. - let NSForm = VLDSTLaneDblFrm.Value; // For disassembly. -} +def VLD3LNq16a: VLD3LN<0b0110, "vld3", "16"> { let Inst{5-4} = 0b10; } def VLD3LNq32a: VLD3LN<0b1010, "vld3", "32"> { let Inst{6-4} = 0b100; } // vld3 to double-spaced odd registers. @@ -369,28 +340,12 @@ def VLD4LNd32 : VLD4LN<0b1011, "vld4", "32"> { let Inst{6} = 0; } // vld4 to double-spaced even registers. -def VLD4LNq16a: VLD4LN<0b0111, "vld4", "16"> { - let Inst{5} = 1; - let NSF = VLDSTLaneDblFrm; // For disassembly. - let NSForm = VLDSTLaneDblFrm.Value; // For disassembly. -} -def VLD4LNq32a: VLD4LN<0b1011, "vld4", "32"> { - let Inst{6} = 1; - let NSF = VLDSTLaneDblFrm; // For disassembly. - let NSForm = VLDSTLaneDblFrm.Value; // For disassembly. -} +def VLD4LNq16a: VLD4LN<0b0111, "vld4", "16"> { let Inst{5} = 1; } +def VLD4LNq32a: VLD4LN<0b1011, "vld4", "32"> { let Inst{6} = 1; } // vld4 to double-spaced odd registers. -def VLD4LNq16b: VLD4LN<0b0111, "vld4", "16"> { - let Inst{5} = 1; - let NSF = VLDSTLaneDblFrm; // For disassembly. - let NSForm = VLDSTLaneDblFrm.Value; // For disassembly. -} -def VLD4LNq32b: VLD4LN<0b1011, "vld4", "32"> { - let Inst{6} = 1; - let NSF = VLDSTLaneDblFrm; // For disassembly. - let NSForm = VLDSTLaneDblFrm.Value; // For disassembly. -} +def VLD4LNq16b: VLD4LN<0b0111, "vld4", "16"> { let Inst{5} = 1; } +def VLD4LNq32b: VLD4LN<0b1011, "vld4", "32"> { let Inst{6} = 1; } // VLD1DUP : Vector Load (single element to all lanes) // VLD2DUP : Vector Load (single 2-element structure to all lanes) @@ -478,10 +433,7 @@ class VST2Ddbl op7_4, string OpcodeStr, string Dt> : NLdSt<0, 0b00, 0b1001, op7_4, (outs), (ins addrmode6:$addr, DPR:$src1, DPR:$src2), IIC_VST, - OpcodeStr, Dt, "\\{$src1, $src2\\}, $addr", "", []> { - let NSF = VLDSTLaneDblFrm; // For disassembly. - let NSForm = VLDSTLaneDblFrm.Value; // For disassembly. -} + OpcodeStr, Dt, "\\{$src1, $src2\\}, $addr", "", []>; def VST2d8D : VST2Ddbl<0b0000, "vst2", "8">; def VST2d16D : VST2Ddbl<0b0100, "vst2", "16">; @@ -496,10 +448,7 @@ : NLdSt<0,0b00,0b0101,op7_4, (outs GPR:$wb), (ins addrmode6:$addr, DPR:$src1, DPR:$src2, DPR:$src3), IIC_VST, OpcodeStr, Dt, "\\{$src1, $src2, $src3\\}, $addr", - "$addr.addr = $wb", []> { - let NSF = VLDSTLaneDblFrm; // For disassembly. - let NSForm = VLDSTLaneDblFrm.Value; // For disassembly. -} + "$addr.addr = $wb", []>; def VST3d8 : VST3D<0b0000, "vst3", "8">; def VST3d16 : VST3D<0b0100, "vst3", "16">; @@ -529,10 +478,7 @@ : NLdSt<0,0b00,0b0001,op7_4, (outs GPR:$wb), (ins addrmode6:$addr, DPR:$src1, DPR:$src2, DPR:$src3, DPR:$src4), IIC_VST, OpcodeStr, Dt, "\\{$src1, $src2, $src3, $src4\\}, $addr", - "$addr.addr = $wb", []> { - let NSF = VLDSTLaneDblFrm; // For disassembly. - let NSForm = VLDSTLaneDblFrm.Value; // For disassembly. -} + "$addr.addr = $wb", []>; def VST4d8 : VST4D<0b0000, "vst4", "8">; def VST4d16 : VST4D<0b0100, "vst4", "16">; @@ -569,28 +515,12 @@ def VST2LNd32 : VST2LN<0b1001, "vst2", "32"> { let Inst{6} = 0; } // vst2 to double-spaced even registers. -def VST2LNq16a: VST2LN<0b0101, "vst2", "16"> { - let Inst{5} = 1; - let NSF = VLDSTLaneDblFrm; // For disassembly. - let NSForm = VLDSTLaneDblFrm.Value; // For disassembly. -} -def VST2LNq32a: VST2LN<0b1001, "vst2", "32"> { - let Inst{6} = 1; - let NSF = VLDSTLaneDblFrm; // For disassembly. - let NSForm = VLDSTLaneDblFrm.Value; // For disassembly. -} +def VST2LNq16a: VST2LN<0b0101, "vst2", "16"> { let Inst{5} = 1; } +def VST2LNq32a: VST2LN<0b1001, "vst2", "32"> { let Inst{6} = 1; } // vst2 to double-spaced odd registers. -def VST2LNq16b: VST2LN<0b0101, "vst2", "16"> { - let Inst{5} = 1; - let NSF = VLDSTLaneDblFrm; // For disassembly. - let NSForm = VLDSTLaneDblFrm.Value; // For disassembly. -} -def VST2LNq32b: VST2LN<0b1001, "vst2", "32"> { - let Inst{6} = 1; - let NSF = VLDSTLaneDblFrm; // For disassembly. - let NSForm = VLDSTLaneDblFrm.Value; // For disassembly. -} +def VST2LNq16b: VST2LN<0b0101, "vst2", "16"> { let Inst{5} = 1; } +def VST2LNq32b: VST2LN<0b1001, "vst2", "32"> { let Inst{6} = 1; } // VST3LN : Vector Store (single 3-element structure from one lane) class VST3LN op11_8, string OpcodeStr, string Dt> @@ -605,28 +535,12 @@ def VST3LNd32 : VST3LN<0b1010, "vst3", "32"> { let Inst{6-4} = 0b000; } // vst3 to double-spaced even registers. -def VST3LNq16a: VST3LN<0b0110, "vst3", "16"> { - let Inst{5-4} = 0b10; - let NSF = VLDSTLaneDblFrm; // For disassembly. - let NSForm = VLDSTLaneDblFrm.Value; // For disassembly. -} -def VST3LNq32a: VST3LN<0b1010, "vst3", "32"> { - let Inst{6-4} = 0b100; - let NSF = VLDSTLaneDblFrm; // For disassembly. - let NSForm = VLDSTLaneDblFrm.Value; // For disassembly. -} +def VST3LNq16a: VST3LN<0b0110, "vst3", "16"> { let Inst{5-4} = 0b10; } +def VST3LNq32a: VST3LN<0b1010, "vst3", "32"> { let Inst{6-4} = 0b100; } // vst3 to double-spaced odd registers. -def VST3LNq16b: VST3LN<0b0110, "vst3", "16"> { - let Inst{5-4} = 0b10; - let NSF = VLDSTLaneDblFrm; // For disassembly. - let NSForm = VLDSTLaneDblFrm.Value; // For disassembly. -} -def VST3LNq32b: VST3LN<0b1010, "vst3", "32"> { - let Inst{6-4} = 0b100; - let NSF = VLDSTLaneDblFrm; // For disassembly. - let NSForm = VLDSTLaneDblFrm.Value; // For disassembly. -} +def VST3LNq16b: VST3LN<0b0110, "vst3", "16"> { let Inst{5-4} = 0b10; } +def VST3LNq32b: VST3LN<0b1010, "vst3", "32"> { let Inst{6-4} = 0b100; } // VST4LN : Vector Store (single 4-element structure from one lane) class VST4LN op11_8, string OpcodeStr, string Dt> @@ -642,28 +556,12 @@ def VST4LNd32 : VST4LN<0b1011, "vst4", "32"> { let Inst{6} = 0; } // vst4 to double-spaced even registers. -def VST4LNq16a: VST4LN<0b0111, "vst4", "16"> { - let Inst{5} = 1; - let NSF = VLDSTLaneDblFrm; // For disassembly. - let NSForm = VLDSTLaneDblFrm.Value; // For disassembly. -} -def VST4LNq32a: VST4LN<0b1011, "vst4", "32"> { - let Inst{6} = 1; - let NSF = VLDSTLaneDblFrm; // For disassembly. - let NSForm = VLDSTLaneDblFrm.Value; // For disassembly. -} +def VST4LNq16a: VST4LN<0b0111, "vst4", "16"> { let Inst{5} = 1; } +def VST4LNq32a: VST4LN<0b1011, "vst4", "32"> { let Inst{6} = 1; } // vst4 to double-spaced odd registers. -def VST4LNq16b: VST4LN<0b0111, "vst4", "16"> { - let Inst{5} = 1; - let NSF = VLDSTLaneDblFrm; // For disassembly. - let NSForm = VLDSTLaneDblFrm.Value; // For disassembly. -} -def VST4LNq32b: VST4LN<0b1011, "vst4", "32"> { - let Inst{6} = 1; - let NSF = VLDSTLaneDblFrm; // For disassembly. - let NSForm = VLDSTLaneDblFrm.Value; // For disassembly. -} +def VST4LNq16b: VST4LN<0b0111, "vst4", "16"> { let Inst{5} = 1; } +def VST4LNq32b: VST4LN<0b1011, "vst4", "32"> { let Inst{6} = 1; } } // mayStore = 1, hasExtraSrcRegAllocReq = 1 @@ -770,18 +668,12 @@ : N2V<0b11, 0b11, op19_18, 0b10, op11_7, 0, 0, (outs DPR:$dst1, DPR:$dst2), (ins DPR:$src1, DPR:$src2), IIC_VPERMD, OpcodeStr, Dt, "$dst1, $dst2", - "$src1 = $dst1, $src2 = $dst2", []> { - let NSF = NVectorShuffleFrm; // For disassembly. - let NSForm = NVectorShuffleFrm.Value; // For disassembly. -} + "$src1 = $dst1, $src2 = $dst2", []>; class N2VQShuffle op19_18, bits<5> op11_7, InstrItinClass itin, string OpcodeStr, string Dt> : N2V<0b11, 0b11, op19_18, 0b10, op11_7, 1, 0, (outs QPR:$dst1, QPR:$dst2), (ins QPR:$src1, QPR:$src2), itin, OpcodeStr, Dt, "$dst1, $dst2", - "$src1 = $dst1, $src2 = $dst2", []> { - let NSF = NVectorShuffleFrm; // For disassembly. - let NSForm = NVectorShuffleFrm.Value; // For disassembly. -} + "$src1 = $dst1, $src2 = $dst2", []>; // Basic 3-register operations: single-, double- and quad-register. class N3VS op21_20, bits<4> op11_8, bit op4, @@ -823,8 +715,6 @@ (Ty (ShOp (Ty DPR:$src1), (Ty (NEONvduplane (Ty DPR_VFP2:$src2), imm:$lane)))))]>{ let isCommutable = 0; - let NSF = NVdVnVmImmMulScalarFrm; // For disassembly. - let NSForm = NVdVnVmImmMulScalarFrm.Value; // For disassembly. } class N3VDSL16 op21_20, bits<4> op11_8, string OpcodeStr, string Dt, ValueType Ty, SDNode ShOp> @@ -835,8 +725,6 @@ (Ty (ShOp (Ty DPR:$src1), (Ty (NEONvduplane (Ty DPR_8:$src2), imm:$lane)))))]> { let isCommutable = 0; - let NSF = NVdVnVmImmMulScalarFrm; // For disassembly. - let NSForm = NVdVnVmImmMulScalarFrm.Value; // For disassembly. } class N3VQ op21_20, bits<4> op11_8, bit op4, @@ -868,8 +756,6 @@ (ResTy (NEONvduplane (OpTy DPR_VFP2:$src2), imm:$lane)))))]> { let isCommutable = 0; - let NSF = NVdVnVmImmMulScalarFrm; // For disassembly. - let NSForm = NVdVnVmImmMulScalarFrm.Value; // For disassembly. } class N3VQSL16 op21_20, bits<4> op11_8, string OpcodeStr, string Dt, ValueType ResTy, ValueType OpTy, SDNode ShOp> @@ -881,8 +767,6 @@ (ResTy (NEONvduplane (OpTy DPR_8:$src2), imm:$lane)))))]> { let isCommutable = 0; - let NSF = NVdVnVmImmMulScalarFrm; // For disassembly. - let NSForm = NVdVnVmImmMulScalarFrm.Value; // For disassembly. } // Basic 3-register intrinsics, both double- and quad-register. @@ -905,8 +789,6 @@ (Ty (NEONvduplane (Ty DPR_VFP2:$src2), imm:$lane)))))]> { let isCommutable = 0; - let NSF = NVdVnVmImmMulScalarFrm; // For disassembly. - let NSForm = NVdVnVmImmMulScalarFrm.Value; // For disassembly. } class N3VDIntSL16 op21_20, bits<4> op11_8, InstrItinClass itin, string OpcodeStr, string Dt, ValueType Ty, Intrinsic IntOp> @@ -918,8 +800,6 @@ (Ty (NEONvduplane (Ty DPR_8:$src2), imm:$lane)))))]> { let isCommutable = 0; - let NSF = NVdVnVmImmMulScalarFrm; // For disassembly. - let NSForm = NVdVnVmImmMulScalarFrm.Value; // For disassembly. } class N3VQInt op21_20, bits<4> op11_8, bit op4, @@ -942,8 +822,6 @@ (ResTy (NEONvduplane (OpTy DPR_VFP2:$src2), imm:$lane)))))]> { let isCommutable = 0; - let NSF = NVdVnVmImmMulScalarFrm; // For disassembly. - let NSForm = NVdVnVmImmMulScalarFrm.Value; // For disassembly. } class N3VQIntSL16 op21_20, bits<4> op11_8, InstrItinClass itin, string OpcodeStr, string Dt, @@ -956,8 +834,6 @@ (ResTy (NEONvduplane (OpTy DPR_8:$src2), imm:$lane)))))]> { let isCommutable = 0; - let NSF = NVdVnVmImmMulScalarFrm; // For disassembly. - let NSForm = NVdVnVmImmMulScalarFrm.Value; // For disassembly. } // Multiply-Add/Sub operations: single-, double- and quad-register. @@ -988,10 +864,7 @@ (Ty (ShOp (Ty DPR:$src1), (Ty (MulOp DPR:$src2, (Ty (NEONvduplane (Ty DPR_VFP2:$src3), - imm:$lane)))))))]> { - let NSF = NVdVnVmImmMulScalarFrm; // For disassembly. - let NSForm = NVdVnVmImmMulScalarFrm.Value; // For disassembly. -} + imm:$lane)))))))]>; class N3VDMulOpSL16 op21_20, bits<4> op11_8, InstrItinClass itin, string OpcodeStr, string Dt, ValueType Ty, SDNode MulOp, SDNode ShOp> @@ -1003,10 +876,7 @@ (Ty (ShOp (Ty DPR:$src1), (Ty (MulOp DPR:$src2, (Ty (NEONvduplane (Ty DPR_8:$src3), - imm:$lane)))))))]> { - let NSF = NVdVnVmImmMulScalarFrm; // For disassembly. - let NSForm = NVdVnVmImmMulScalarFrm.Value; // For disassembly. -} + imm:$lane)))))))]>; class N3VQMulOp op21_20, bits<4> op11_8, bit op4, InstrItinClass itin, string OpcodeStr, string Dt, ValueType Ty, @@ -1027,10 +897,7 @@ (ResTy (ShOp (ResTy QPR:$src1), (ResTy (MulOp QPR:$src2, (ResTy (NEONvduplane (OpTy DPR_VFP2:$src3), - imm:$lane)))))))]> { - let NSF = NVdVnVmImmMulScalarFrm; // For disassembly. - let NSForm = NVdVnVmImmMulScalarFrm.Value; // For disassembly. -} + imm:$lane)))))))]>; class N3VQMulOpSL16 op21_20, bits<4> op11_8, InstrItinClass itin, string OpcodeStr, string Dt, ValueType ResTy, ValueType OpTy, @@ -1043,10 +910,7 @@ (ResTy (ShOp (ResTy QPR:$src1), (ResTy (MulOp QPR:$src2, (ResTy (NEONvduplane (OpTy DPR_8:$src3), - imm:$lane)))))))]> { - let NSF = NVdVnVmImmMulScalarFrm; // For disassembly. - let NSForm = NVdVnVmImmMulScalarFrm.Value; // For disassembly. -} + imm:$lane)))))))]>; // Neon 3-argument intrinsics, both double- and quad-register. // The destination register is also used as the first source operand register. @@ -1132,10 +996,7 @@ [(set (ResTy QPR:$dst), (ResTy (IntOp (OpTy DPR:$src1), (OpTy (NEONvduplane (OpTy DPR_VFP2:$src2), - imm:$lane)))))]> { - let NSF = NVdVnVmImmMulScalarFrm; // For disassembly. - let NSForm = NVdVnVmImmMulScalarFrm.Value; // For disassembly. -} + imm:$lane)))))]>; class N3VLIntSL16 op21_20, bits<4> op11_8, InstrItinClass itin, string OpcodeStr, string Dt, ValueType ResTy, ValueType OpTy, Intrinsic IntOp> @@ -1145,10 +1006,7 @@ [(set (ResTy QPR:$dst), (ResTy (IntOp (OpTy DPR:$src1), (OpTy (NEONvduplane (OpTy DPR_8:$src2), - imm:$lane)))))]> { - let NSF = NVdVnVmImmMulScalarFrm; // For disassembly. - let NSForm = NVdVnVmImmMulScalarFrm.Value; // For disassembly. -} + imm:$lane)))))]>; // Wide 3-register intrinsics. class N3VWInt op21_20, bits<4> op11_8, bit op4, @@ -1197,10 +1055,6 @@ OpcodeStr, Dt, "$dst, $src2", "$src1 = $dst", [(set QPR:$dst, (ResTy (IntOp (ResTy QPR:$src1), (OpTy QPR:$src2))))]>; -// This is a big let * in block to mark these instructions NVectorShiftFrm to -// help the disassembler. -let NSF = NVectorShiftFrm, NSForm = NVectorShiftFrm.Value in { - // Shift by immediate, // both double- and quad-register. class N2VDSh op11_8, bit op7, bit op4, @@ -1218,6 +1072,16 @@ OpcodeStr, Dt, "$dst, $src, $SIMM", "", [(set QPR:$dst, (Ty (OpNode (Ty QPR:$src), (i32 imm:$SIMM))))]>; +// Long shift by immediate. +class N2VLSh op11_8, bit op7, bit op6, bit op4, + string OpcodeStr, string Dt, + ValueType ResTy, ValueType OpTy, SDNode OpNode> + : N2VImm; + // Narrow shift by immediate. class N2VNSh op11_8, bit op7, bit op6, bit op4, InstrItinClass itin, string OpcodeStr, string Dt, @@ -1260,26 +1124,8 @@ OpcodeStr, Dt, "$dst, $src2, $SIMM", "$src1 = $dst", [(set QPR:$dst, (Ty (ShOp QPR:$src1, QPR:$src2, (i32 imm:$SIMM))))]>; -} // End of "let NSF = NVectorShiftFrm, ..." - -// Long shift by immediate. -class N2VLSh op11_8, bit op7, bit op6, bit op4, - string OpcodeStr, string Dt, - ValueType ResTy, ValueType OpTy, SDNode OpNode> - : N2VImm { - // This has a different interpretation of the shift amount encoding than - // NVectorShiftFrm. - let NSF = NVectorShift2Frm; // For disassembly. - let NSForm = NVectorShift2Frm.Value; // For disassembly. -} - // Convert, with fractional bits immediate, // both double- and quad-register. -let NSF = NVdVmImmVCVTFrm, NSForm = NVdVmImmVCVTFrm.Value in { class N2VCvtD op11_8, bit op7, bit op4, string OpcodeStr, string Dt, ValueType ResTy, ValueType OpTy, Intrinsic IntOp> @@ -1294,7 +1140,6 @@ (outs QPR:$dst), (ins QPR:$src, i32imm:$SIMM), IIC_VUNAQ, OpcodeStr, Dt, "$dst, $src, $SIMM", "", [(set QPR:$dst, (ResTy (IntOp (OpTy QPR:$src), (i32 imm:$SIMM))))]>; -} //===----------------------------------------------------------------------===// // Multiclasses @@ -1505,60 +1350,6 @@ v2i64, v2i64, IntOp, Commutable>; } -// Same as N3VInt_QHSD, except they're for Vector Shift (Register) Instructions. -// D:Vd M:Vm N:Vn (notice that M:Vm is the first operand) -// This helps the disassembler. -let NSF = NVdVnVmImmVectorShiftFrm, NSForm = NVdVnVmImmVectorShiftFrm.Value in { -multiclass N3VInt_HS2 op11_8, bit op4, - InstrItinClass itinD16, InstrItinClass itinD32, - InstrItinClass itinQ16, InstrItinClass itinQ32, - string OpcodeStr, string Dt, - Intrinsic IntOp, bit Commutable = 0> { - // 64-bit vector types. - def v4i16 : N3VDInt; - def v2i32 : N3VDInt; - - // 128-bit vector types. - def v8i16 : N3VQInt; - def v4i32 : N3VQInt; -} -multiclass N3VInt_QHS2 op11_8, bit op4, - InstrItinClass itinD16, InstrItinClass itinD32, - InstrItinClass itinQ16, InstrItinClass itinQ32, - string OpcodeStr, string Dt, - Intrinsic IntOp, bit Commutable = 0> - : N3VInt_HS2 { - def v8i8 : N3VDInt; - def v16i8 : N3VQInt; -} -multiclass N3VInt_QHSD2 op11_8, bit op4, - InstrItinClass itinD16, InstrItinClass itinD32, - InstrItinClass itinQ16, InstrItinClass itinQ32, - string OpcodeStr, string Dt, - Intrinsic IntOp, bit Commutable = 0> - : N3VInt_QHS2 { - def v1i64 : N3VDInt; - def v2i64 : N3VQInt; -} -} // Neon Narrowing 3-register vector intrinsics, // source operand element sizes of 16, 32 and 64 bits: @@ -1828,47 +1619,6 @@ // imm6 = xxxxxx } -// Same as N2VSh_QHSD, except the instructions have a differnt interpretation of -// the shift amount. This helps the disassembler. -let NSF = NVectorShift2Frm, NSForm = NVectorShift2Frm.Value in { -multiclass N2VSh_QHSD2 op11_8, bit op4, - InstrItinClass itin, string OpcodeStr, string Dt, - SDNode OpNode> { - // 64-bit vector types. - def v8i8 : N2VDSh { - let Inst{21-19} = 0b001; // imm6 = 001xxx - } - def v4i16 : N2VDSh { - let Inst{21-20} = 0b01; // imm6 = 01xxxx - } - def v2i32 : N2VDSh { - let Inst{21} = 0b1; // imm6 = 1xxxxx - } - def v1i64 : N2VDSh; - // imm6 = xxxxxx - - // 128-bit vector types. - def v16i8 : N2VQSh { - let Inst{21-19} = 0b001; // imm6 = 001xxx - } - def v8i16 : N2VQSh { - let Inst{21-20} = 0b01; // imm6 = 01xxxx - } - def v4i32 : N2VQSh { - let Inst{21} = 0b1; // imm6 = 1xxxxx - } - def v2i64 : N2VQSh; - // imm6 = xxxxxx -} -} // Neon Shift-Accumulate vector operations, // element sizes of 8, 16, 32 and 64 bits: @@ -1949,47 +1699,6 @@ // imm6 = xxxxxx } -// Same as N2VShIns_QHSD, except the instructions have a differnt interpretation -// of the shift amount. This helps the disassembler. -let NSF = NVectorShift2Frm, NSForm = NVectorShift2Frm.Value in { -multiclass N2VShIns_QHSD2 op11_8, bit op4, - string OpcodeStr, SDNode ShOp> { - // 64-bit vector types. - def v8i8 : N2VDShIns { - let Inst{21-19} = 0b001; // imm6 = 001xxx - } - def v4i16 : N2VDShIns { - let Inst{21-20} = 0b01; // imm6 = 01xxxx - } - def v2i32 : N2VDShIns { - let Inst{21} = 0b1; // imm6 = 1xxxxx - } - def v1i64 : N2VDShIns; - // imm6 = xxxxxx - - // 128-bit vector types. - def v16i8 : N2VQShIns { - let Inst{21-19} = 0b001; // imm6 = 001xxx - } - def v8i16 : N2VQShIns { - let Inst{21-20} = 0b01; // imm6 = 01xxxx - } - def v4i32 : N2VQShIns { - let Inst{21} = 0b1; // imm6 = 1xxxxx - } - def v2i64 : N2VQShIns; - // imm6 = xxxxxx -} -} - // Neon Shift Long operations, // element sizes of 8, 16, 32 bits: multiclass N2VLSh_QHS op11_8, bit op7, bit op6, @@ -2620,21 +2329,18 @@ // Vector Shifts. // VSHL : Vector Shift -defm VSHLs : N3VInt_QHSD2<0,0, 0b0100, 0, IIC_VSHLiD, IIC_VSHLiD, IIC_VSHLiQ, - IIC_VSHLiQ, "vshl", "s", int_arm_neon_vshifts, 0>; -defm VSHLu : N3VInt_QHSD2<1,0, 0b0100, 0, IIC_VSHLiD, IIC_VSHLiD, IIC_VSHLiQ, - IIC_VSHLiQ, "vshl", "u", int_arm_neon_vshiftu, 0>; +defm VSHLs : N3VInt_QHSD<0, 0, 0b0100, 0, IIC_VSHLiD, IIC_VSHLiD, IIC_VSHLiQ, + IIC_VSHLiQ, "vshl", "s", int_arm_neon_vshifts, 0>; +defm VSHLu : N3VInt_QHSD<1, 0, 0b0100, 0, IIC_VSHLiD, IIC_VSHLiD, IIC_VSHLiQ, + IIC_VSHLiQ, "vshl", "u", int_arm_neon_vshiftu, 0>; // VSHL : Vector Shift Left (Immediate) -// (disassembly note: this has a different interpretation of the shift amont) -defm VSHLi : N2VSh_QHSD2<0, 1, 0b0101, 1, IIC_VSHLiD, "vshl", "i", NEONvshl>; +defm VSHLi : N2VSh_QHSD<0, 1, 0b0101, 1, IIC_VSHLiD, "vshl", "i", NEONvshl>; // VSHR : Vector Shift Right (Immediate) defm VSHRs : N2VSh_QHSD<0, 1, 0b0000, 1, IIC_VSHLiD, "vshr", "s", NEONvshrs>; defm VSHRu : N2VSh_QHSD<1, 1, 0b0000, 1, IIC_VSHLiD, "vshr", "u", NEONvshru>; // VSHLL : Vector Shift Left Long -// (disassembly note: this has a different interpretation of the shift amont) defm VSHLLs : N2VLSh_QHS<0, 1, 0b1010, 0, 0, 1, "vshll", "s", NEONvshlls>; -// (disassembly note: this has a different interpretation of the shift amont) defm VSHLLu : N2VLSh_QHS<1, 1, 0b1010, 0, 0, 1, "vshll", "u", NEONvshllu>; // VSHLL : Vector Shift Left Long (with maximum shift count) @@ -2644,8 +2350,6 @@ : N2VLSh { let Inst{21-16} = op21_16; - let NSF = NVdVmImmVSHLLFrm; // For disassembly. - let NSForm = NVdVmImmVSHLLFrm.Value; // For disassembly. } def VSHLLi8 : N2VLShMax<1, 1, 0b110010, 0b0011, 0, 0, 0, "vshll", "i8", v8i16, v8i8, NEONvshlli>; @@ -2659,10 +2363,10 @@ NEONvshrn>; // VRSHL : Vector Rounding Shift -defm VRSHLs : N3VInt_QHSD2<0,0,0b0101,0,IIC_VSHLi4D, IIC_VSHLi4D, IIC_VSHLi4Q, - IIC_VSHLi4Q,"vrshl", "s", int_arm_neon_vrshifts,0>; -defm VRSHLu : N3VInt_QHSD2<1,0,0b0101,0,IIC_VSHLi4D, IIC_VSHLi4D, IIC_VSHLi4Q, - IIC_VSHLi4Q,"vrshl", "u", int_arm_neon_vrshiftu,0>; +defm VRSHLs : N3VInt_QHSD<0,0,0b0101,0, IIC_VSHLi4D, IIC_VSHLi4D, IIC_VSHLi4Q, + IIC_VSHLi4Q, "vrshl", "s", int_arm_neon_vrshifts,0>; +defm VRSHLu : N3VInt_QHSD<1,0,0b0101,0, IIC_VSHLi4D, IIC_VSHLi4D, IIC_VSHLi4Q, + IIC_VSHLi4Q, "vrshl", "u", int_arm_neon_vrshiftu,0>; // VRSHR : Vector Rounding Shift Right defm VRSHRs : N2VSh_QHSD<0,1,0b0010,1, IIC_VSHLi4D, "vrshr", "s", NEONvrshrs>; defm VRSHRu : N2VSh_QHSD<1,1,0b0010,1, IIC_VSHLi4D, "vrshr", "u", NEONvrshru>; @@ -2672,18 +2376,15 @@ NEONvrshrn>; // VQSHL : Vector Saturating Shift -defm VQSHLs : N3VInt_QHSD2<0,0,0b0100,1,IIC_VSHLi4D, IIC_VSHLi4D, IIC_VSHLi4Q, - IIC_VSHLi4Q, "vqshl", "s", int_arm_neon_vqshifts,0>; -defm VQSHLu : N3VInt_QHSD2<1,0,0b0100,1,IIC_VSHLi4D, IIC_VSHLi4D, IIC_VSHLi4Q, - IIC_VSHLi4Q, "vqshl", "u", int_arm_neon_vqshiftu,0>; +defm VQSHLs : N3VInt_QHSD<0,0,0b0100,1, IIC_VSHLi4D, IIC_VSHLi4D, IIC_VSHLi4Q, + IIC_VSHLi4Q, "vqshl", "s", int_arm_neon_vqshifts,0>; +defm VQSHLu : N3VInt_QHSD<1,0,0b0100,1, IIC_VSHLi4D, IIC_VSHLi4D, IIC_VSHLi4Q, + IIC_VSHLi4Q, "vqshl", "u", int_arm_neon_vqshiftu,0>; // VQSHL : Vector Saturating Shift Left (Immediate) -// (disassembly note: this has a different interpretation of the shift amont) -defm VQSHLsi : N2VSh_QHSD2<0,1,0b0111,1, IIC_VSHLi4D, "vqshl", "s", NEONvqshls>; -// (disassembly note: this has a different interpretation of the shift amont) -defm VQSHLui : N2VSh_QHSD2<1,1,0b0111,1, IIC_VSHLi4D, "vqshl", "u", NEONvqshlu>; +defm VQSHLsi : N2VSh_QHSD<0,1,0b0111,1, IIC_VSHLi4D, "vqshl", "s", NEONvqshls>; +defm VQSHLui : N2VSh_QHSD<1,1,0b0111,1, IIC_VSHLi4D, "vqshl", "u", NEONvqshlu>; // VQSHLU : Vector Saturating Shift Left (Immediate, Unsigned) -// (disassembly note: this has a different interpretation of the shift amont) -defm VQSHLsu : N2VSh_QHSD2<1,1,0b0110,1, IIC_VSHLi4D, "vqshlu","s",NEONvqshlsu>; +defm VQSHLsu : N2VSh_QHSD<1,1,0b0110,1, IIC_VSHLi4D, "vqshlu","s",NEONvqshlsu>; // VQSHRN : Vector Saturating Shift Right and Narrow defm VQSHRNs : N2VNSh_HSD<0, 1, 0b1001, 0, 0, 1, IIC_VSHLi4D, "vqshrn", "s", @@ -2696,12 +2397,12 @@ NEONvqshrnsu>; // VQRSHL : Vector Saturating Rounding Shift -defm VQRSHLs : N3VInt_QHSD2<0,0,0b0101,1, IIC_VSHLi4D, IIC_VSHLi4D, IIC_VSHLi4Q, - IIC_VSHLi4Q, "vqrshl", "s", - int_arm_neon_vqrshifts, 0>; -defm VQRSHLu : N3VInt_QHSD2<1,0,0b0101,1, IIC_VSHLi4D, IIC_VSHLi4D, IIC_VSHLi4Q, - IIC_VSHLi4Q, "vqrshl", "u", - int_arm_neon_vqrshiftu, 0>; +defm VQRSHLs : N3VInt_QHSD<0,0,0b0101,1, IIC_VSHLi4D, IIC_VSHLi4D, IIC_VSHLi4Q, + IIC_VSHLi4Q, "vqrshl", "s", + int_arm_neon_vqrshifts, 0>; +defm VQRSHLu : N3VInt_QHSD<1,0,0b0101,1, IIC_VSHLi4D, IIC_VSHLi4D, IIC_VSHLi4Q, + IIC_VSHLi4Q, "vqrshl", "u", + int_arm_neon_vqrshiftu, 0>; // VQRSHRN : Vector Saturating Rounding Shift Right and Narrow defm VQRSHRNs : N2VNSh_HSD<0, 1, 0b1001, 0, 1, 1, IIC_VSHLi4D, "vqrshrn", "s", @@ -2721,8 +2422,7 @@ defm VRSRAu : N2VShAdd_QHSD<1, 1, 0b0011, 1, "vrsra", "u", NEONvrshru>; // VSLI : Vector Shift Left and Insert -// (disassembly note: this has a different interpretation of the shift amont) -defm VSLI : N2VShIns_QHSD2<1, 1, 0b0101, 1, "vsli", NEONvsli>; +defm VSLI : N2VShIns_QHSD<1, 1, 0b0101, 1, "vsli", NEONvsli>; // VSRI : Vector Shift Right and Insert defm VSRI : N2VShIns_QHSD<1, 1, 0b0100, 1, "vsri", NEONvsri>; @@ -2818,13 +2518,10 @@ // VMOV : Vector Move (Register) -// Mark these instructions as 2-register instructions to help the disassembler. -let NSF = NVdVmImmFrm, NSForm = NVdVmImmFrm.Value in { def VMOVDneon: N3VX<0, 0, 0b10, 0b0001, 0, 1, (outs DPR:$dst), (ins DPR:$src), IIC_VMOVD, "vmov", "$dst, $src", "", []>; def VMOVQ : N3VX<0, 0, 0b10, 0b0001, 1, 1, (outs QPR:$dst), (ins QPR:$src), IIC_VMOVD, "vmov", "$dst, $src", "", []>; -} // VMOV : Vector Move (Immediate) @@ -3065,7 +2762,6 @@ // VDUP : Vector Duplicate Lane (from scalar to all elements) -let NSF = NVdVmImmVDupLaneFrm, NSForm = NVdVmImmVDupLaneFrm.Value in { class VDUPLND op19_18, bits<2> op17_16, string OpcodeStr, string Dt, ValueType Ty> : N2V<0b11, 0b11, op19_18, op17_16, 0b11000, 0, 0, @@ -3079,7 +2775,6 @@ (outs QPR:$dst), (ins DPR:$src, nohash_imm:$lane), IIC_VMOVD, OpcodeStr, Dt, "$dst, $src[$lane]", "", [(set QPR:$dst, (ResTy (NEONvduplane (OpTy DPR:$src), imm:$lane)))]>; -} // Inst{19-16} is partially specified depending on the element size. @@ -3148,37 +2843,24 @@ // Vector Conversions. -let NSF = NVdVmImmVCVTFrm, NSForm = NVdVmImmVCVTFrm.Value in { -class N2VDX op24_23, bits<2> op21_20, bits<2> op19_18, - bits<2> op17_16, bits<5> op11_7, bit op4, string OpcodeStr, - string Dt, ValueType ResTy, ValueType OpTy, SDNode OpNode> - : N2VD; -class N2VQX op24_23, bits<2> op21_20, bits<2> op19_18, - bits<2> op17_16, bits<5> op11_7, bit op4, string OpcodeStr, - string Dt, ValueType ResTy, ValueType OpTy, SDNode OpNode> - : N2VQ; -} - // VCVT : Vector Convert Between Floating-Point and Integers -def VCVTf2sd : N2VDX<0b11, 0b11, 0b10, 0b11, 0b01110, 0, "vcvt", "s32.f32", - v2i32, v2f32, fp_to_sint>; -def VCVTf2ud : N2VDX<0b11, 0b11, 0b10, 0b11, 0b01111, 0, "vcvt", "u32.f32", - v2i32, v2f32, fp_to_uint>; -def VCVTs2fd : N2VDX<0b11, 0b11, 0b10, 0b11, 0b01100, 0, "vcvt", "f32.s32", - v2f32, v2i32, sint_to_fp>; -def VCVTu2fd : N2VDX<0b11, 0b11, 0b10, 0b11, 0b01101, 0, "vcvt", "f32.u32", - v2f32, v2i32, uint_to_fp>; - -def VCVTf2sq : N2VQX<0b11, 0b11, 0b10, 0b11, 0b01110, 0, "vcvt", "s32.f32", - v4i32, v4f32, fp_to_sint>; -def VCVTf2uq : N2VQX<0b11, 0b11, 0b10, 0b11, 0b01111, 0, "vcvt", "u32.f32", - v4i32, v4f32, fp_to_uint>; -def VCVTs2fq : N2VQX<0b11, 0b11, 0b10, 0b11, 0b01100, 0, "vcvt", "f32.s32", - v4f32, v4i32, sint_to_fp>; -def VCVTu2fq : N2VQX<0b11, 0b11, 0b10, 0b11, 0b01101, 0, "vcvt", "f32.u32", - v4f32, v4i32, uint_to_fp>; +def VCVTf2sd : N2VD<0b11, 0b11, 0b10, 0b11, 0b01110, 0, "vcvt", "s32.f32", + v2i32, v2f32, fp_to_sint>; +def VCVTf2ud : N2VD<0b11, 0b11, 0b10, 0b11, 0b01111, 0, "vcvt", "u32.f32", + v2i32, v2f32, fp_to_uint>; +def VCVTs2fd : N2VD<0b11, 0b11, 0b10, 0b11, 0b01100, 0, "vcvt", "f32.s32", + v2f32, v2i32, sint_to_fp>; +def VCVTu2fd : N2VD<0b11, 0b11, 0b10, 0b11, 0b01101, 0, "vcvt", "f32.u32", + v2f32, v2i32, uint_to_fp>; + +def VCVTf2sq : N2VQ<0b11, 0b11, 0b10, 0b11, 0b01110, 0, "vcvt", "s32.f32", + v4i32, v4f32, fp_to_sint>; +def VCVTf2uq : N2VQ<0b11, 0b11, 0b10, 0b11, 0b01111, 0, "vcvt", "u32.f32", + v4i32, v4f32, fp_to_uint>; +def VCVTs2fq : N2VQ<0b11, 0b11, 0b10, 0b11, 0b01100, 0, "vcvt", "f32.s32", + v4f32, v4i32, sint_to_fp>; +def VCVTu2fq : N2VQ<0b11, 0b11, 0b10, 0b11, 0b01101, 0, "vcvt", "f32.u32", + v4f32, v4i32, uint_to_fp>; // VCVT : Vector Convert Between Floating-Point and Fixed-Point. def VCVTf2xsd : N2VCvtD<0, 1, 0b1111, 0, 1, "vcvt", "s32.f32", @@ -3263,8 +2945,6 @@ // VEXT : Vector Extract -let NSF = NVdVnVmImmVectorExtractFrm, - NSForm = NVdVnVmImmVectorExtractFrm.Value in { class VEXTd : N3V<0,1,0b11,{?,?,?,?},0,0, (outs DPR:$dst), (ins DPR:$lhs, DPR:$rhs, i32imm:$index), IIC_VEXTD, @@ -3278,7 +2958,6 @@ OpcodeStr, Dt, "$dst, $lhs, $rhs, $index", "", [(set QPR:$dst, (Ty (NEONvext (Ty QPR:$lhs), (Ty QPR:$rhs), imm:$index)))]>; -} def VEXTd8 : VEXTd<"vext", "8", v8i8>; def VEXTd16 : VEXTd<"vext", "16", v4i16>; @@ -3322,8 +3001,6 @@ // Vector Table Lookup and Table Extension. -let NSF = VTBLFrm, NSForm = VTBLFrm.Value in { - // VTBL : Vector Table Lookup def VTBL1 : N3V<1,1,0b11,0b1000,0,0, (outs DPR:$dst), @@ -3380,8 +3057,6 @@ DPR:$tbl2, DPR:$tbl3, DPR:$tbl4, DPR:$src)))]>; } // hasExtraSrcRegAllocReq = 1 -} // End of "let NSF = VTBLFrm, ..." - //===----------------------------------------------------------------------===// // NEON instructions for single-precision FP math //===----------------------------------------------------------------------===// Modified: llvm/trunk/lib/Target/ARM/AsmPrinter/ARMAsmPrinter.cpp URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Target/ARM/AsmPrinter/ARMAsmPrinter.cpp?rev=98640&r1=98639&r2=98640&view=diff ============================================================================== --- llvm/trunk/lib/Target/ARM/AsmPrinter/ARMAsmPrinter.cpp (original) +++ llvm/trunk/lib/Target/ARM/AsmPrinter/ARMAsmPrinter.cpp Tue Mar 16 11:59:47 2010 @@ -120,7 +120,7 @@ void printT2AddrModeImm8Operand(const MachineInstr *MI, int OpNum); void printT2AddrModeImm8s4Operand(const MachineInstr *MI, int OpNum); void printT2AddrModeImm8OffsetOperand(const MachineInstr *MI, int OpNum); - void printT2AddrModeImm8s4OffsetOperand(const MachineInstr *MI, int OpNum); + void printT2AddrModeImm8s4OffsetOperand(const MachineInstr *MI, int OpNum) {} void printT2AddrModeSoRegOperand(const MachineInstr *MI, int OpNum); void printCPSOptionOperand(const MachineInstr *MI, int OpNum) {} @@ -431,16 +431,16 @@ O << "[" << getRegisterName(MO1.getReg()); if (!MO2.getReg()) { - if (ARM_AM::getAM2Offset(MO3.getImm())) // Don't print +0. + if (ARM_AM::getAM2Offset(MO3.getImm())) // Don't print +0. O << ", #" - << ARM_AM::getAddrOpcStr(ARM_AM::getAM2Op(MO3.getImm())) + << (char)ARM_AM::getAM2Op(MO3.getImm()) << ARM_AM::getAM2Offset(MO3.getImm()); O << "]"; return; } O << ", " - << ARM_AM::getAddrOpcStr(ARM_AM::getAM2Op(MO3.getImm())) + << (char)ARM_AM::getAM2Op(MO3.getImm()) << getRegisterName(MO2.getReg()); if (unsigned ShImm = ARM_AM::getAM2Offset(MO3.getImm())) @@ -458,12 +458,12 @@ unsigned ImmOffs = ARM_AM::getAM2Offset(MO2.getImm()); assert(ImmOffs && "Malformed indexed load / store!"); O << "#" - << ARM_AM::getAddrOpcStr(ARM_AM::getAM2Op(MO2.getImm())) + << (char)ARM_AM::getAM2Op(MO2.getImm()) << ImmOffs; return; } - O << ARM_AM::getAddrOpcStr(ARM_AM::getAM2Op(MO2.getImm())) + O << (char)ARM_AM::getAM2Op(MO2.getImm()) << getRegisterName(MO1.getReg()); if (unsigned ShImm = ARM_AM::getAM2Offset(MO2.getImm())) @@ -490,7 +490,7 @@ if (unsigned ImmOffs = ARM_AM::getAM3Offset(MO3.getImm())) O << ", #" - << ARM_AM::getAddrOpcStr(ARM_AM::getAM3Op(MO3.getImm())) + << (char)ARM_AM::getAM3Op(MO3.getImm()) << ImmOffs; O << "]"; } @@ -508,7 +508,7 @@ unsigned ImmOffs = ARM_AM::getAM3Offset(MO2.getImm()); assert(ImmOffs && "Malformed indexed load / store!"); O << "#" - << ARM_AM::getAddrOpcStr(ARM_AM::getAM3Op(MO2.getImm())) + << (char)ARM_AM::getAM3Op(MO2.getImm()) << ImmOffs; } @@ -558,7 +558,7 @@ if (unsigned ImmOffs = ARM_AM::getAM5Offset(MO2.getImm())) { O << ", #" - << ARM_AM::getAddrOpcStr(ARM_AM::getAM5Op(MO2.getImm())) + << (char)ARM_AM::getAM5Op(MO2.getImm()) << ImmOffs*4; } O << "]"; @@ -594,7 +594,7 @@ const MachineOperand &MO1 = MI->getOperand(Op); assert(TargetRegisterInfo::isPhysicalRegister(MO1.getReg())); - O << "[pc, " << getRegisterName(MO1.getReg()) << "]"; + O << "[pc, +" << getRegisterName(MO1.getReg()) << "]"; } void @@ -617,11 +617,10 @@ ARMAsmPrinter::printThumbITMask(const MachineInstr *MI, int Op) { // (3 - the number of trailing zeros) is the number of then / else. unsigned Mask = MI->getOperand(Op).getImm(); - unsigned CondBit0 = Mask >> 4 & 1; unsigned NumTZ = CountTrailingZeros_32(Mask); assert(NumTZ <= 3 && "Invalid IT mask!"); for (unsigned Pos = 3, e = NumTZ; Pos > e; --Pos) { - bool T = ((Mask >> Pos) & 1) == CondBit0; + bool T = (Mask & (1 << Pos)) == 0; if (T) O << 't'; else @@ -653,7 +652,7 @@ if (MO3.getReg()) O << ", " << getRegisterName(MO3.getReg()); else if (unsigned ImmOffs = MO2.getImm()) - O << ", #" << ImmOffs * Scale; + O << ", #+" << ImmOffs * Scale; O << "]"; } @@ -675,7 +674,7 @@ const MachineOperand &MO2 = MI->getOperand(Op+1); O << "[" << getRegisterName(MO1.getReg()); if (unsigned ImmOffs = MO2.getImm()) - O << ", #" << ImmOffs*4; + O << ", #+" << ImmOffs*4; O << "]"; } @@ -711,7 +710,7 @@ unsigned OffImm = MO2.getImm(); if (OffImm) // Don't print +0. - O << ", #" << OffImm; + O << ", #+" << OffImm; O << "]"; } @@ -727,7 +726,7 @@ if (OffImm < 0) O << ", #-" << -OffImm; else if (OffImm > 0) - O << ", #" << OffImm; + O << ", #+" << OffImm; O << "]"; } @@ -743,7 +742,7 @@ if (OffImm < 0) O << ", #-" << -OffImm * 4; else if (OffImm > 0) - O << ", #" << OffImm * 4; + O << ", #+" << OffImm * 4; O << "]"; } @@ -755,18 +754,7 @@ if (OffImm < 0) O << "#-" << -OffImm; else if (OffImm > 0) - O << "#" << OffImm; -} - -void ARMAsmPrinter::printT2AddrModeImm8s4OffsetOperand(const MachineInstr *MI, - int OpNum) { - const MachineOperand &MO1 = MI->getOperand(OpNum); - int32_t OffImm = (int32_t)MO1.getImm() / 4; - // Don't print +0. - if (OffImm < 0) - O << "#-" << -OffImm * 4; - else if (OffImm > 0) - O << "#" << OffImm * 4; + O << "#+" << OffImm; } void ARMAsmPrinter::printT2AddrModeSoRegOperand(const MachineInstr *MI, Modified: llvm/trunk/lib/Target/ARM/AsmPrinter/ARMInstPrinter.cpp URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Target/ARM/AsmPrinter/ARMInstPrinter.cpp?rev=98640&r1=98639&r2=98640&view=diff ============================================================================== --- llvm/trunk/lib/Target/ARM/AsmPrinter/ARMInstPrinter.cpp (original) +++ llvm/trunk/lib/Target/ARM/AsmPrinter/ARMInstPrinter.cpp Tue Mar 16 11:59:47 2010 @@ -28,165 +28,7 @@ #undef MachineInstr #undef ARMAsmPrinter -static unsigned NextReg(unsigned Reg) { - switch (Reg) { - case ARM::D0: - return ARM::D1; - case ARM::D1: - return ARM::D2; - case ARM::D2: - return ARM::D3; - case ARM::D3: - return ARM::D4; - case ARM::D4: - return ARM::D5; - case ARM::D5: - return ARM::D6; - case ARM::D6: - return ARM::D7; - case ARM::D7: - return ARM::D8; - case ARM::D8: - return ARM::D9; - case ARM::D9: - return ARM::D10; - case ARM::D10: - return ARM::D11; - case ARM::D11: - return ARM::D12; - case ARM::D12: - return ARM::D13; - case ARM::D13: - return ARM::D14; - case ARM::D14: - return ARM::D15; - case ARM::D15: - return ARM::D16; - case ARM::D16: - return ARM::D17; - case ARM::D17: - return ARM::D18; - case ARM::D18: - return ARM::D19; - case ARM::D19: - return ARM::D20; - case ARM::D20: - return ARM::D21; - case ARM::D21: - return ARM::D22; - case ARM::D22: - return ARM::D23; - case ARM::D23: - return ARM::D24; - case ARM::D24: - return ARM::D25; - case ARM::D25: - return ARM::D26; - case ARM::D26: - return ARM::D27; - case ARM::D27: - return ARM::D28; - case ARM::D28: - return ARM::D29; - case ARM::D29: - return ARM::D30; - case ARM::D30: - return ARM::D31; - - default: - assert(0 && "Unexpected register enum"); - } -} - -void ARMInstPrinter::printInst(const MCInst *MI) { - // Check for MOVs and print canonical forms, instead. - if (MI->getOpcode() == ARM::MOVs) { - const MCOperand &Dst = MI->getOperand(0); - const MCOperand &MO1 = MI->getOperand(1); - const MCOperand &MO2 = MI->getOperand(2); - const MCOperand &MO3 = MI->getOperand(3); - - O << '\t' << ARM_AM::getShiftOpcStr(ARM_AM::getSORegShOp(MO3.getImm())); - printSBitModifierOperand(MI, 6); - printPredicateOperand(MI, 4); - - O << '\t' << getRegisterName(Dst.getReg()) - << ", " << getRegisterName(MO1.getReg()); - - if (ARM_AM::getSORegShOp(MO3.getImm()) == ARM_AM::rrx) - return; - - O << ", "; - - if (MO2.getReg()) { - O << getRegisterName(MO2.getReg()); - assert(ARM_AM::getSORegOffset(MO3.getImm()) == 0); - } else { - O << "#" << ARM_AM::getSORegOffset(MO3.getImm()); - } - return; - } - - // A8.6.123 PUSH - if ((MI->getOpcode() == ARM::STM || MI->getOpcode() == ARM::t2STM_UPD) && - MI->getOperand(0).getReg() == ARM::SP) { - const unsigned IdxOffset = MI->getOpcode() == ARM::STM ? 0 : 1; - const MCOperand &MO1 = MI->getOperand(IdxOffset + 1); - if (ARM_AM::getAM4WBFlag(MO1.getImm()) && - ARM_AM::getAM4SubMode(MO1.getImm()) == ARM_AM::db) { - O << '\t' << "push"; - printPredicateOperand(MI, IdxOffset + 2); - O << '\t'; - printRegisterList(MI, IdxOffset + 4); - return; - } - } - - // A8.6.122 POP - if ((MI->getOpcode() == ARM::LDM || MI->getOpcode() == ARM::t2LDM_UPD) && - MI->getOperand(0).getReg() == ARM::SP) { - const unsigned IdxOffset = MI->getOpcode() == ARM::LDM ? 0 : 1; - const MCOperand &MO1 = MI->getOperand(IdxOffset + 1); - if (ARM_AM::getAM4WBFlag(MO1.getImm()) && - ARM_AM::getAM4SubMode(MO1.getImm()) == ARM_AM::ia) { - O << '\t' << "pop"; - printPredicateOperand(MI, IdxOffset + 2); - O << '\t'; - printRegisterList(MI, IdxOffset + 4); - return; - } - } - - // A8.6.355 VPUSH - if ((MI->getOpcode() == ARM::VSTMS || MI->getOpcode() == ARM::VSTMD) && - MI->getOperand(0).getReg() == ARM::SP) { - const MCOperand &MO1 = MI->getOperand(1); - if (ARM_AM::getAM5WBFlag(MO1.getImm()) && - ARM_AM::getAM5SubMode(MO1.getImm()) == ARM_AM::db) { - O << '\t' << "vpush"; - printPredicateOperand(MI, 2); - O << '\t'; - printRegisterList(MI, 4); - return; - } - } - - // A8.6.354 VPOP - if ((MI->getOpcode() == ARM::VLDMS || MI->getOpcode() == ARM::VLDMD) && - MI->getOperand(0).getReg() == ARM::SP) { - const MCOperand &MO1 = MI->getOperand(1); - if (ARM_AM::getAM5WBFlag(MO1.getImm()) && - ARM_AM::getAM5SubMode(MO1.getImm()) == ARM_AM::ia) { - O << '\t' << "vpop"; - printPredicateOperand(MI, 2); - O << '\t'; - printRegisterList(MI, 4); - return; - } - } - - printInstruction(MI); - } +void ARMInstPrinter::printInst(const MCInst *MI) { printInstruction(MI); } void ARMInstPrinter::printOperand(const MCInst *MI, unsigned OpNo, const char *Modifier) { @@ -194,9 +36,6 @@ if (Op.isReg()) { unsigned Reg = Op.getReg(); if (Modifier && strcmp(Modifier, "dregpair") == 0) { - O << '{' << getRegisterName(Reg) << ", " - << getRegisterName(NextReg(Reg)) << '}'; -#if 0 // FIXME: Breaks e.g. ARM/vmul.ll. assert(0); /* @@ -205,7 +44,6 @@ O << '{' << getRegisterName(DRegLo) << ',' << getRegisterName(DRegHi) << '}';*/ -#endif } else if (Modifier && strcmp(Modifier, "lane") == 0) { assert(0); /* @@ -218,9 +56,7 @@ O << getRegisterName(Reg); } } else if (Op.isImm()) { - bool isCallOp = Modifier && !strcmp(Modifier, "call"); - assert(isCallOp || - ((Modifier == 0 || Modifier[0] == 0) && "No modifiers supported")); + assert((Modifier == 0 || Modifier[0] == 0) && "No modifiers supported"); O << '#' << Op.getImm(); } else { assert((Modifier == 0 || Modifier[0] == 0) && "No modifiers supported"); @@ -306,17 +142,17 @@ O << "[" << getRegisterName(MO1.getReg()); if (!MO2.getReg()) { - if (ARM_AM::getAM2Offset(MO3.getImm())) // Don't print +0. + if (ARM_AM::getAM2Offset(MO3.getImm())) // Don't print +0. O << ", #" - << ARM_AM::getAddrOpcStr(ARM_AM::getAM2Op(MO3.getImm())) - << ARM_AM::getAM2Offset(MO3.getImm()); + << (char)ARM_AM::getAM2Op(MO3.getImm()) + << ARM_AM::getAM2Offset(MO3.getImm()); O << "]"; return; } O << ", " - << ARM_AM::getAddrOpcStr(ARM_AM::getAM2Op(MO3.getImm())) - << getRegisterName(MO2.getReg()); + << (char)ARM_AM::getAM2Op(MO3.getImm()) + << getRegisterName(MO2.getReg()); if (unsigned ShImm = ARM_AM::getAM2Offset(MO3.getImm())) O << ", " @@ -333,14 +169,11 @@ if (!MO1.getReg()) { unsigned ImmOffs = ARM_AM::getAM2Offset(MO2.getImm()); assert(ImmOffs && "Malformed indexed load / store!"); - O << '#' - << ARM_AM::getAddrOpcStr(ARM_AM::getAM2Op(MO2.getImm())) - << ImmOffs; + O << '#' << (char)ARM_AM::getAM2Op(MO2.getImm()) << ImmOffs; return; } - O << ARM_AM::getAddrOpcStr(ARM_AM::getAM2Op(MO2.getImm())) - << getRegisterName(MO1.getReg()); + O << (char)ARM_AM::getAM2Op(MO2.getImm()) << getRegisterName(MO1.getReg()); if (unsigned ShImm = ARM_AM::getAM2Offset(MO2.getImm())) O << ", " @@ -363,8 +196,8 @@ if (unsigned ImmOffs = ARM_AM::getAM3Offset(MO3.getImm())) O << ", #" - << ARM_AM::getAddrOpcStr(ARM_AM::getAM3Op(MO3.getImm())) - << ImmOffs; + << (char)ARM_AM::getAM3Op(MO3.getImm()) + << ImmOffs; O << ']'; } @@ -381,9 +214,9 @@ unsigned ImmOffs = ARM_AM::getAM3Offset(MO2.getImm()); assert(ImmOffs && "Malformed indexed load / store!"); - O << '#' - << ARM_AM::getAddrOpcStr(ARM_AM::getAM3Op(MO2.getImm())) - << ImmOffs; + O << "#" + << (char)ARM_AM::getAM3Op(MO2.getImm()) + << ImmOffs; } @@ -431,7 +264,7 @@ if (unsigned ImmOffs = ARM_AM::getAM5Offset(MO2.getImm())) { O << ", #" - << ARM_AM::getAddrOpcStr(ARM_AM::getAM5Op(MO2.getImm())) + << (char)ARM_AM::getAM5Op(MO2.getImm()) << ImmOffs*4; } O << "]"; @@ -470,56 +303,14 @@ void ARMInstPrinter::printRegisterList(const MCInst *MI, unsigned OpNum) { O << "{"; - for (unsigned i = OpNum, e = MI->getNumOperands(); i != e; ++i) { - if (i != OpNum) O << ", "; + // Always skip the first operand, it's the optional (and implicit writeback). + for (unsigned i = OpNum+1, e = MI->getNumOperands(); i != e; ++i) { + if (i != OpNum+1) O << ", "; O << getRegisterName(MI->getOperand(i).getReg()); } O << "}"; } -void ARMInstPrinter::printCPSOptionOperand(const MCInst *MI, unsigned OpNum) { - const MCOperand &Op = MI->getOperand(OpNum); - unsigned option = Op.getImm(); - unsigned mode = option & 31; - bool changemode = option >> 5 & 1; - unsigned AIF = option >> 6 & 7; - unsigned imod = option >> 9 & 3; - if (imod == 2) - O << "ie"; - else if (imod == 3) - O << "id"; - O << '\t'; - if (imod > 1) { - if (AIF & 4) O << 'a'; - if (AIF & 2) O << 'i'; - if (AIF & 1) O << 'f'; - if (AIF > 0 && changemode) O << ", "; - } - if (changemode) - O << '#' << mode; -} - -void ARMInstPrinter::printMSRMaskOperand(const MCInst *MI, unsigned OpNum) { - const MCOperand &Op = MI->getOperand(OpNum); - unsigned Mask = Op.getImm(); - if (Mask) { - O << '_'; - if (Mask & 8) O << 'f'; - if (Mask & 4) O << 's'; - if (Mask & 2) O << 'x'; - if (Mask & 1) O << 'c'; - } -} - -void ARMInstPrinter::printNegZeroOperand(const MCInst *MI, unsigned OpNum){ - const MCOperand &Op = MI->getOperand(OpNum); - O << '#'; - if (Op.getImm() < 0) - O << '-' << (-Op.getImm() - 1); - else - O << Op.getImm(); -} - void ARMInstPrinter::printPredicateOperand(const MCInst *MI, unsigned OpNum) { ARMCC::CondCodes CC = (ARMCC::CondCodes)MI->getOperand(OpNum).getImm(); if (CC != ARMCC::AL) @@ -561,191 +352,3 @@ void ARMInstPrinter::printThumbS4ImmOperand(const MCInst *MI, unsigned OpNum) { O << "#" << MI->getOperand(OpNum).getImm() * 4; } - -void ARMInstPrinter::printThumbITMask(const MCInst *MI, unsigned OpNum) { - // (3 - the number of trailing zeros) is the number of then / else. - unsigned Mask = MI->getOperand(OpNum).getImm(); - unsigned CondBit0 = Mask >> 4 & 1; - unsigned NumTZ = CountTrailingZeros_32(Mask); - assert(NumTZ <= 3 && "Invalid IT mask!"); - for (unsigned Pos = 3, e = NumTZ; Pos > e; --Pos) { - bool T = ((Mask >> Pos) & 1) == CondBit0; - if (T) - O << 't'; - else - O << 'e'; - } -} - -void ARMInstPrinter::printThumbAddrModeRROperand(const MCInst *MI, unsigned Op) -{ - const MCOperand &MO1 = MI->getOperand(Op); - const MCOperand &MO2 = MI->getOperand(Op+1); - O << "[" << getRegisterName(MO1.getReg()); - O << ", " << getRegisterName(MO2.getReg()) << "]"; -} - -void ARMInstPrinter::printThumbAddrModeRI5Operand(const MCInst *MI, unsigned Op, - unsigned Scale) { - const MCOperand &MO1 = MI->getOperand(Op); - const MCOperand &MO2 = MI->getOperand(Op+1); - const MCOperand &MO3 = MI->getOperand(Op+2); - - if (!MO1.isReg()) { // FIXME: This is for CP entries, but isn't right. - printOperand(MI, Op); - return; - } - - O << "[" << getRegisterName(MO1.getReg()); - if (MO3.getReg()) - O << ", " << getRegisterName(MO3.getReg()); - else if (unsigned ImmOffs = MO2.getImm()) - O << ", #" << ImmOffs * Scale; - O << "]"; -} - -void ARMInstPrinter::printThumbAddrModeS1Operand(const MCInst *MI, unsigned Op) -{ - printThumbAddrModeRI5Operand(MI, Op, 1); -} - -void ARMInstPrinter::printThumbAddrModeS2Operand(const MCInst *MI, unsigned Op) -{ - printThumbAddrModeRI5Operand(MI, Op, 2); -} - -void ARMInstPrinter::printThumbAddrModeS4Operand(const MCInst *MI, unsigned Op) -{ - printThumbAddrModeRI5Operand(MI, Op, 4); -} - -void ARMInstPrinter::printThumbAddrModeSPOperand(const MCInst *MI,unsigned Op) { - const MCOperand &MO1 = MI->getOperand(Op); - const MCOperand &MO2 = MI->getOperand(Op+1); - O << "[" << getRegisterName(MO1.getReg()); - if (unsigned ImmOffs = MO2.getImm()) - O << ", #" << ImmOffs*4; - O << "]"; -} - -void ARMInstPrinter::printTBAddrMode(const MCInst *MI, unsigned OpNum) { - O << "[pc, " << getRegisterName(MI->getOperand(OpNum).getReg()); - if (MI->getOpcode() == ARM::t2TBH) - O << ", lsl #1"; - O << ']'; -} - -// Constant shifts t2_so_reg is a 2-operand unit corresponding to the Thumb2 -// register with shift forms. -// REG 0 0 - e.g. R5 -// REG IMM, SH_OPC - e.g. R5, LSL #3 -void ARMInstPrinter::printT2SOOperand(const MCInst *MI, unsigned OpNum) { - const MCOperand &MO1 = MI->getOperand(OpNum); - const MCOperand &MO2 = MI->getOperand(OpNum+1); - - unsigned Reg = MO1.getReg(); - O << getRegisterName(Reg); - - // Print the shift opc. - O << ", " - << ARM_AM::getShiftOpcStr(ARM_AM::getSORegShOp(MO2.getImm())) - << " "; - - assert(MO2.isImm() && "Not a valid t2_so_reg value!"); - O << "#" << ARM_AM::getSORegOffset(MO2.getImm()); -} - -void ARMInstPrinter::printT2AddrModeImm12Operand(const MCInst *MI, - unsigned OpNum) { - const MCOperand &MO1 = MI->getOperand(OpNum); - const MCOperand &MO2 = MI->getOperand(OpNum+1); - - O << "[" << getRegisterName(MO1.getReg()); - - unsigned OffImm = MO2.getImm(); - if (OffImm) // Don't print +0. - O << ", #" << OffImm; - O << "]"; -} - -void ARMInstPrinter::printT2AddrModeImm8Operand(const MCInst *MI, - unsigned OpNum) { - const MCOperand &MO1 = MI->getOperand(OpNum); - const MCOperand &MO2 = MI->getOperand(OpNum+1); - - O << "[" << getRegisterName(MO1.getReg()); - - int32_t OffImm = (int32_t)MO2.getImm(); - // Don't print +0. - if (OffImm < 0) - O << ", #-" << -OffImm; - else if (OffImm > 0) - O << ", #" << OffImm; - O << "]"; -} - -void ARMInstPrinter::printT2AddrModeImm8s4Operand(const MCInst *MI, - unsigned OpNum) { - const MCOperand &MO1 = MI->getOperand(OpNum); - const MCOperand &MO2 = MI->getOperand(OpNum+1); - - O << "[" << getRegisterName(MO1.getReg()); - - int32_t OffImm = (int32_t)MO2.getImm() / 4; - // Don't print +0. - if (OffImm < 0) - O << ", #-" << -OffImm * 4; - else if (OffImm > 0) - O << ", #" << OffImm * 4; - O << "]"; -} - -void ARMInstPrinter::printT2AddrModeImm8OffsetOperand(const MCInst *MI, - unsigned OpNum) { - const MCOperand &MO1 = MI->getOperand(OpNum); - int32_t OffImm = (int32_t)MO1.getImm(); - // Don't print +0. - if (OffImm < 0) - O << "#-" << -OffImm; - else if (OffImm > 0) - O << "#" << OffImm; -} - -void ARMInstPrinter::printT2AddrModeImm8s4OffsetOperand(const MCInst *MI, - unsigned OpNum) { - const MCOperand &MO1 = MI->getOperand(OpNum); - int32_t OffImm = (int32_t)MO1.getImm() / 4; - // Don't print +0. - if (OffImm < 0) - O << "#-" << -OffImm * 4; - else if (OffImm > 0) - O << "#" << OffImm * 4; -} - -void ARMInstPrinter::printT2AddrModeSoRegOperand(const MCInst *MI, - unsigned OpNum) { - const MCOperand &MO1 = MI->getOperand(OpNum); - const MCOperand &MO2 = MI->getOperand(OpNum+1); - const MCOperand &MO3 = MI->getOperand(OpNum+2); - - O << "[" << getRegisterName(MO1.getReg()); - - assert(MO2.getReg() && "Invalid so_reg load / store address!"); - O << ", " << getRegisterName(MO2.getReg()); - - unsigned ShAmt = MO3.getImm(); - if (ShAmt) { - assert(ShAmt <= 3 && "Not a valid Thumb2 addressing mode!"); - O << ", lsl #" << ShAmt; - } - O << "]"; -} - -void ARMInstPrinter::printVFPf32ImmOperand(const MCInst *MI, unsigned OpNum) { - O << '#' << MI->getOperand(OpNum).getImm(); -} - -void ARMInstPrinter::printVFPf64ImmOperand(const MCInst *MI, unsigned OpNum) { - O << '#' << MI->getOperand(OpNum).getImm(); -} - Modified: llvm/trunk/lib/Target/ARM/AsmPrinter/ARMInstPrinter.h URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Target/ARM/AsmPrinter/ARMInstPrinter.h?rev=98640&r1=98639&r2=98640&view=diff ============================================================================== --- llvm/trunk/lib/Target/ARM/AsmPrinter/ARMInstPrinter.h (original) +++ llvm/trunk/lib/Target/ARM/AsmPrinter/ARMInstPrinter.h Tue Mar 16 11:59:47 2010 @@ -54,26 +54,26 @@ void printBitfieldInvMaskImmOperand(const MCInst *MI, unsigned OpNum); void printThumbS4ImmOperand(const MCInst *MI, unsigned OpNum); - void printThumbITMask(const MCInst *MI, unsigned OpNum); - void printThumbAddrModeRROperand(const MCInst *MI, unsigned OpNum); + void printThumbITMask(const MCInst *MI, unsigned OpNum) {} + void printThumbAddrModeRROperand(const MCInst *MI, unsigned OpNum) {} void printThumbAddrModeRI5Operand(const MCInst *MI, unsigned OpNum, - unsigned Scale); - void printThumbAddrModeS1Operand(const MCInst *MI, unsigned OpNum); - void printThumbAddrModeS2Operand(const MCInst *MI, unsigned OpNum); - void printThumbAddrModeS4Operand(const MCInst *MI, unsigned OpNum); - void printThumbAddrModeSPOperand(const MCInst *MI, unsigned OpNum); + unsigned Scale) {} + void printThumbAddrModeS1Operand(const MCInst *MI, unsigned OpNum) {} + void printThumbAddrModeS2Operand(const MCInst *MI, unsigned OpNum) {} + void printThumbAddrModeS4Operand(const MCInst *MI, unsigned OpNum) {} + void printThumbAddrModeSPOperand(const MCInst *MI, unsigned OpNum) {} - void printT2SOOperand(const MCInst *MI, unsigned OpNum); - void printT2AddrModeImm12Operand(const MCInst *MI, unsigned OpNum); - void printT2AddrModeImm8Operand(const MCInst *MI, unsigned OpNum); - void printT2AddrModeImm8s4Operand(const MCInst *MI, unsigned OpNum); - void printT2AddrModeImm8OffsetOperand(const MCInst *MI, unsigned OpNum); - void printT2AddrModeImm8s4OffsetOperand(const MCInst *MI, unsigned OpNum); - void printT2AddrModeSoRegOperand(const MCInst *MI, unsigned OpNum); + void printT2SOOperand(const MCInst *MI, unsigned OpNum) {} + void printT2AddrModeImm12Operand(const MCInst *MI, unsigned OpNum) {} + void printT2AddrModeImm8Operand(const MCInst *MI, unsigned OpNum) {} + void printT2AddrModeImm8s4Operand(const MCInst *MI, unsigned OpNum) {} + void printT2AddrModeImm8OffsetOperand(const MCInst *MI, unsigned OpNum) {} + void printT2AddrModeImm8s4OffsetOperand(const MCInst *MI, unsigned OpNum) {} + void printT2AddrModeSoRegOperand(const MCInst *MI, unsigned OpNum) {} - void printCPSOptionOperand(const MCInst *MI, unsigned OpNum); - void printMSRMaskOperand(const MCInst *MI, unsigned OpNum); - void printNegZeroOperand(const MCInst *MI, unsigned OpNum); + void printCPSOptionOperand(const MCInst *MI, unsigned OpNum) {} + void printMSRMaskOperand(const MCInst *MI, unsigned OpNum) {} + void printNegZeroOperand(const MCInst *MI, unsigned OpNum) {} void printPredicateOperand(const MCInst *MI, unsigned OpNum); void printMandatoryPredicateOperand(const MCInst *MI, unsigned OpNum); void printSBitModifierOperand(const MCInst *MI, unsigned OpNum); @@ -82,10 +82,10 @@ const char *Modifier); void printJTBlockOperand(const MCInst *MI, unsigned OpNum) {} void printJT2BlockOperand(const MCInst *MI, unsigned OpNum) {} - void printTBAddrMode(const MCInst *MI, unsigned OpNum); + void printTBAddrMode(const MCInst *MI, unsigned OpNum) {} void printNoHashImmediate(const MCInst *MI, unsigned OpNum); - void printVFPf32ImmOperand(const MCInst *MI, unsigned OpNum); - void printVFPf64ImmOperand(const MCInst *MI, unsigned OpNum); + void printVFPf32ImmOperand(const MCInst *MI, int OpNum) {} + void printVFPf64ImmOperand(const MCInst *MI, int OpNum) {} void printHex8ImmOperand(const MCInst *MI, int OpNum) {} void printHex16ImmOperand(const MCInst *MI, int OpNum) {} void printHex32ImmOperand(const MCInst *MI, int OpNum) {} Modified: llvm/trunk/lib/Target/ARM/Makefile URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Target/ARM/Makefile?rev=98640&r1=98639&r2=98640&view=diff ============================================================================== --- llvm/trunk/lib/Target/ARM/Makefile (original) +++ llvm/trunk/lib/Target/ARM/Makefile Tue Mar 16 11:59:47 2010 @@ -16,9 +16,8 @@ ARMGenRegisterInfo.inc ARMGenInstrNames.inc \ ARMGenInstrInfo.inc ARMGenAsmWriter.inc \ ARMGenDAGISel.inc ARMGenSubtarget.inc \ - ARMGenCodeEmitter.inc ARMGenCallingConv.inc \ - ARMGenDisassemblerTables.inc + ARMGenCodeEmitter.inc ARMGenCallingConv.inc -DIRS = AsmPrinter AsmParser Disassembler TargetInfo +DIRS = AsmPrinter AsmParser TargetInfo include $(LEVEL)/Makefile.common Modified: llvm/trunk/lib/Target/ARM/Thumb2ITBlockPass.cpp URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Target/ARM/Thumb2ITBlockPass.cpp?rev=98640&r1=98639&r2=98640&view=diff ============================================================================== --- llvm/trunk/lib/Target/ARM/Thumb2ITBlockPass.cpp (original) +++ llvm/trunk/lib/Target/ARM/Thumb2ITBlockPass.cpp Tue Mar 16 11:59:47 2010 @@ -78,16 +78,14 @@ DebugLoc ndl = NMI->getDebugLoc(); unsigned NPredReg = 0; ARMCC::CondCodes NCC = getPredicate(NMI, NPredReg); - if (NCC == CC || NCC == OCC) - Mask |= (NCC & 1) << Pos; - else + if (NCC == OCC) { + Mask |= (1 << Pos); + } else if (NCC != CC) break; --Pos; ++MBBI; } Mask |= (1 << Pos); - // Tag along (firstcond[0] << 4) with the mask. - Mask |= (CC & 1) << 4; MIB.addImm(Mask); Modified = true; ++NumITs; Modified: llvm/trunk/test/CodeGen/ARM/2009-10-27-double-align.ll URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/CodeGen/ARM/2009-10-27-double-align.ll?rev=98640&r1=98639&r2=98640&view=diff ============================================================================== --- llvm/trunk/test/CodeGen/ARM/2009-10-27-double-align.ll (original) +++ llvm/trunk/test/CodeGen/ARM/2009-10-27-double-align.ll Tue Mar 16 11:59:47 2010 @@ -4,8 +4,8 @@ define arm_aapcscc void @g() { entry: -;CHECK: [sp, #8] -;CHECK: [sp, #12] +;CHECK: [sp, #+8] +;CHECK: [sp, #+12] ;CHECK: [sp] tail call arm_aapcscc void (i8*, ...)* @f(i8* getelementptr ([1 x i8]* @.str, i32 0, i32 0), i32 1, double 2.000000e+00, i32 3, double 4.000000e+00) ret void Modified: llvm/trunk/test/CodeGen/ARM/2009-10-30.ll URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/CodeGen/ARM/2009-10-30.ll?rev=98640&r1=98639&r2=98640&view=diff ============================================================================== --- llvm/trunk/test/CodeGen/ARM/2009-10-30.ll (original) +++ llvm/trunk/test/CodeGen/ARM/2009-10-30.ll Tue Mar 16 11:59:47 2010 @@ -6,7 +6,7 @@ entry: ;CHECK: sub sp, sp, #4 ;CHECK: add r{{[0-9]+}}, sp, #8 -;CHECK: str r{{[0-9]+}}, [sp], #4 +;CHECK: str r{{[0-9]+}}, [sp], #+4 ;CHECK: bx lr %ap = alloca i8*, align 4 %ap1 = bitcast i8** %ap to i8* Modified: llvm/trunk/test/CodeGen/ARM/arm-negative-stride.ll URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/CodeGen/ARM/arm-negative-stride.ll?rev=98640&r1=98639&r2=98640&view=diff ============================================================================== --- llvm/trunk/test/CodeGen/ARM/arm-negative-stride.ll (original) +++ llvm/trunk/test/CodeGen/ARM/arm-negative-stride.ll Tue Mar 16 11:59:47 2010 @@ -5,7 +5,7 @@ define void @test(i32* %P, i32 %A, i32 %i) nounwind { entry: -; CHECK: str r1, [{{r.*}}, {{r.*}}, lsl #2] +; CHECK: str r1, [{{r.*}}, +{{r.*}}, lsl #2] icmp eq i32 %i, 0 ; :0 [#uses=1] br i1 %0, label %return, label %bb Modified: llvm/trunk/test/CodeGen/ARM/globals.ll URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/CodeGen/ARM/globals.ll?rev=98640&r1=98639&r2=98640&view=diff ============================================================================== --- llvm/trunk/test/CodeGen/ARM/globals.ll (original) +++ llvm/trunk/test/CodeGen/ARM/globals.ll Tue Mar 16 11:59:47 2010 @@ -41,7 +41,7 @@ ; DarwinPIC: _test1: ; DarwinPIC: ldr r0, LCPI1_0 ; DarwinPIC: LPC1_0: -; DarwinPIC: ldr r0, [pc, r0] +; DarwinPIC: ldr r0, [pc, +r0] ; DarwinPIC: ldr r0, [r0] ; DarwinPIC: bx lr @@ -63,7 +63,7 @@ ; LinuxPIC: .LPC1_0: ; LinuxPIC: add r0, pc, r0 -; LinuxPIC: ldr r0, [r1, r0] +; LinuxPIC: ldr r0, [r1, +r0] ; LinuxPIC: ldr r0, [r0] ; LinuxPIC: bx lr Modified: llvm/trunk/test/CodeGen/ARM/ldrd.ll URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/CodeGen/ARM/ldrd.ll?rev=98640&r1=98639&r2=98640&view=diff ============================================================================== --- llvm/trunk/test/CodeGen/ARM/ldrd.ll (original) +++ llvm/trunk/test/CodeGen/ARM/ldrd.ll Tue Mar 16 11:59:47 2010 @@ -10,10 +10,10 @@ ;V6: ldrd r2, [r2] ;V5: ldr r3, [r2] -;V5: ldr r2, [r2, #4] +;V5: ldr r2, [r2, #+4] ;EABI: ldr r3, [r2] -;EABI: ldr r2, [r2, #4] +;EABI: ldr r2, [r2, #+4] %0 = load i64** @b, align 4 %1 = load i64* %0, align 4 Modified: llvm/trunk/test/CodeGen/ARM/str_pre-2.ll URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/CodeGen/ARM/str_pre-2.ll?rev=98640&r1=98639&r2=98640&view=diff ============================================================================== --- llvm/trunk/test/CodeGen/ARM/str_pre-2.ll (original) +++ llvm/trunk/test/CodeGen/ARM/str_pre-2.ll Tue Mar 16 11:59:47 2010 @@ -1,5 +1,5 @@ ; RUN: llc < %s -mtriple=arm-linux-gnu | grep {str.*\\!} -; RUN: llc < %s -mtriple=arm-linux-gnu | grep {ldr.*\\\[.*\], #4} +; RUN: llc < %s -mtriple=arm-linux-gnu | grep {ldr.*\\\[.*\], #+4} @b = external global i64* Modified: llvm/trunk/test/CodeGen/ARM/tls2.ll URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/CodeGen/ARM/tls2.ll?rev=98640&r1=98639&r2=98640&view=diff ============================================================================== --- llvm/trunk/test/CodeGen/ARM/tls2.ll (original) +++ llvm/trunk/test/CodeGen/ARM/tls2.ll Tue Mar 16 11:59:47 2010 @@ -7,7 +7,7 @@ define i32 @f() { ; CHECK-NONPIC: f: -; CHECK-NONPIC: ldr {{r.}}, [pc, {{r.}}] +; CHECK-NONPIC: ldr {{r.}}, [pc, +{{r.}}] ; CHECK-NONPIC: i(gottpoff) ; CHECK-PIC: f: ; CHECK-PIC: __tls_get_addr @@ -18,7 +18,7 @@ define i32* @g() { ; CHECK-NONPIC: g: -; CHECK-NONPIC: ldr {{r.}}, [pc, {{r.}}] +; CHECK-NONPIC: ldr {{r.}}, [pc, +{{r.}}] ; CHECK-NONPIC: i(gottpoff) ; CHECK-PIC: g: ; CHECK-PIC: __tls_get_addr Modified: llvm/trunk/test/CodeGen/Thumb2/ldr-str-imm12.ll URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/CodeGen/Thumb2/ldr-str-imm12.ll?rev=98640&r1=98639&r2=98640&view=diff ============================================================================== --- llvm/trunk/test/CodeGen/Thumb2/ldr-str-imm12.ll (original) +++ llvm/trunk/test/CodeGen/Thumb2/ldr-str-imm12.ll Tue Mar 16 11:59:47 2010 @@ -22,7 +22,7 @@ define arm_apcscc %union.rec* @Manifest(%union.rec* %x, %union.rec* %env, %struct.STYLE* %style, %union.rec** %bthr, %union.rec** %fthr, %union.rec** %target, %union.rec** %crs, i32 %ok, i32 %need_expand, %union.rec** %enclose, i32 %fcr) nounwind { entry: -; CHECK: ldr.w r9, [r7, #28] +; CHECK: ldr.w r9, [r7, #+28] %xgaps.i = alloca [32 x %union.rec*], align 4 ; <[32 x %union.rec*]*> [#uses=0] %ycomp.i = alloca [32 x %union.rec*], align 4 ; <[32 x %union.rec*]*> [#uses=0] br i1 false, label %bb, label %bb20 @@ -50,9 +50,9 @@ bb420: ; preds = %bb20, %bb20 ; CHECK: bb420 ; CHECK: str r{{[0-7]}}, [sp] -; CHECK: str r{{[0-7]}}, [sp, #4] -; CHECK: str r{{[0-7]}}, [sp, #8] -; CHECK: str{{(.w)?}} r{{[0-9]+}}, [sp, #24] +; CHECK: str r{{[0-7]}}, [sp, #+4] +; CHECK: str r{{[0-7]}}, [sp, #+8] +; CHECK: str{{(.w)?}} r{{[0-9]+}}, [sp, #+24] store %union.rec* null, %union.rec** @zz_hold, align 4 store %union.rec* null, %union.rec** @zz_res, align 4 store %union.rec* %x, %union.rec** @zz_hold, align 4 Modified: llvm/trunk/test/CodeGen/Thumb2/thumb2-ldr.ll URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/CodeGen/Thumb2/thumb2-ldr.ll?rev=98640&r1=98639&r2=98640&view=diff ============================================================================== --- llvm/trunk/test/CodeGen/Thumb2/thumb2-ldr.ll (original) +++ llvm/trunk/test/CodeGen/Thumb2/thumb2-ldr.ll Tue Mar 16 11:59:47 2010 @@ -11,7 +11,7 @@ define i32 @f2(i32* %v) { entry: ; CHECK: f2: -; CHECK: ldr.w r0, [r0, #4092] +; CHECK: ldr.w r0, [r0, #+4092] %tmp2 = getelementptr i32* %v, i32 1023 %tmp = load i32* %tmp2 ret i32 %tmp Modified: llvm/trunk/test/CodeGen/Thumb2/thumb2-ldrh.ll URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/CodeGen/Thumb2/thumb2-ldrh.ll?rev=98640&r1=98639&r2=98640&view=diff ============================================================================== --- llvm/trunk/test/CodeGen/Thumb2/thumb2-ldrh.ll (original) +++ llvm/trunk/test/CodeGen/Thumb2/thumb2-ldrh.ll Tue Mar 16 11:59:47 2010 @@ -11,7 +11,7 @@ define i16 @f2(i16* %v) { entry: ; CHECK: f2: -; CHECK: ldrh.w r0, [r0, #2046] +; CHECK: ldrh.w r0, [r0, #+2046] %tmp2 = getelementptr i16* %v, i16 1023 %tmp = load i16* %tmp2 ret i16 %tmp Modified: llvm/trunk/test/CodeGen/Thumb2/thumb2-str.ll URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/CodeGen/Thumb2/thumb2-str.ll?rev=98640&r1=98639&r2=98640&view=diff ============================================================================== --- llvm/trunk/test/CodeGen/Thumb2/thumb2-str.ll (original) +++ llvm/trunk/test/CodeGen/Thumb2/thumb2-str.ll Tue Mar 16 11:59:47 2010 @@ -9,7 +9,7 @@ define i32 @f2(i32 %a, i32* %v) { ; CHECK: f2: -; CHECK: str.w r0, [r1, #4092] +; CHECK: str.w r0, [r1, #+4092] %tmp2 = getelementptr i32* %v, i32 1023 store i32 %a, i32* %tmp2 ret i32 %a Modified: llvm/trunk/test/CodeGen/Thumb2/thumb2-str_pre.ll URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/CodeGen/Thumb2/thumb2-str_pre.ll?rev=98640&r1=98639&r2=98640&view=diff ============================================================================== --- llvm/trunk/test/CodeGen/Thumb2/thumb2-str_pre.ll (original) +++ llvm/trunk/test/CodeGen/Thumb2/thumb2-str_pre.ll Tue Mar 16 11:59:47 2010 @@ -2,7 +2,7 @@ define void @test1(i32* %X, i32* %A, i32** %dest) { ; CHECK: test1 -; CHECK: str r1, [r0, #16]! +; CHECK: str r1, [r0, #+16]! %B = load i32* %A ; [#uses=1] %Y = getelementptr i32* %X, i32 4 ; [#uses=2] store i32 %B, i32* %Y @@ -12,7 +12,7 @@ define i16* @test2(i16* %X, i32* %A) { ; CHECK: test2 -; CHECK: strh r1, [r0, #8]! +; CHECK: strh r1, [r0, #+8]! %B = load i32* %A ; [#uses=1] %Y = getelementptr i16* %X, i32 4 ; [#uses=2] %tmp = trunc i32 %B to i16 ; [#uses=1] Modified: llvm/trunk/test/CodeGen/Thumb2/thumb2-strb.ll URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/CodeGen/Thumb2/thumb2-strb.ll?rev=98640&r1=98639&r2=98640&view=diff ============================================================================== --- llvm/trunk/test/CodeGen/Thumb2/thumb2-strb.ll (original) +++ llvm/trunk/test/CodeGen/Thumb2/thumb2-strb.ll Tue Mar 16 11:59:47 2010 @@ -9,7 +9,7 @@ define i8 @f2(i8 %a, i8* %v) { ; CHECK: f2: -; CHECK: strb.w r0, [r1, #4092] +; CHECK: strb.w r0, [r1, #+4092] %tmp2 = getelementptr i8* %v, i32 4092 store i8 %a, i8* %tmp2 ret i8 %a Modified: llvm/trunk/test/CodeGen/Thumb2/thumb2-strh.ll URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/CodeGen/Thumb2/thumb2-strh.ll?rev=98640&r1=98639&r2=98640&view=diff ============================================================================== --- llvm/trunk/test/CodeGen/Thumb2/thumb2-strh.ll (original) +++ llvm/trunk/test/CodeGen/Thumb2/thumb2-strh.ll Tue Mar 16 11:59:47 2010 @@ -9,7 +9,7 @@ define i16 @f2(i16 %a, i16* %v) { ; CHECK: f2: -; CHECK: strh.w r0, [r1, #4092] +; CHECK: strh.w r0, [r1, #+4092] %tmp2 = getelementptr i16* %v, i32 2046 store i16 %a, i16* %tmp2 ret i16 %a Modified: llvm/trunk/utils/TableGen/DisassemblerEmitter.cpp URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/utils/TableGen/DisassemblerEmitter.cpp?rev=98640&r1=98639&r2=98640&view=diff ============================================================================== --- llvm/trunk/utils/TableGen/DisassemblerEmitter.cpp (original) +++ llvm/trunk/utils/TableGen/DisassemblerEmitter.cpp Tue Mar 16 11:59:47 2010 @@ -12,8 +12,6 @@ #include "Record.h" #include "X86DisassemblerTables.h" #include "X86RecognizableInstr.h" -#include "RISCDisassemblerEmitter.h" - using namespace llvm; using namespace llvm::X86Disassembler; @@ -126,12 +124,6 @@ return; } - // Fixed-instruction-length targets use a common disassembler. - if (Target.getName() == "ARM") { - RISCDisassemblerEmitter(Records).run(OS); - return; - } - throw TGError(Target.getTargetRecord()->getLoc(), "Unable to generate disassembler for this target"); } Removed: llvm/trunk/utils/TableGen/RISCDisassemblerEmitter.cpp URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/utils/TableGen/RISCDisassemblerEmitter.cpp?rev=98639&view=auto ============================================================================== --- llvm/trunk/utils/TableGen/RISCDisassemblerEmitter.cpp (original) +++ llvm/trunk/utils/TableGen/RISCDisassemblerEmitter.cpp (removed) @@ -1,1743 +0,0 @@ -//===- RISCDisassemblerEmitter.cpp - Disassembler Generator ---------------===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// -// FIXME: document -// -//===----------------------------------------------------------------------===// - -#define DEBUG_TYPE "risc-disassembler-emitter" - -#include "RISCDisassemblerEmitter.h" -#include "CodeGenTarget.h" -#include "Record.h" -#include "llvm/ADT/StringExtras.h" -#include "llvm/Support/Debug.h" -#include "llvm/Support/raw_ostream.h" - -#include -#include -#include -#include -#include -#include - -using namespace llvm; - -//////////////////////////////////// -// Utility classes / structures // -//////////////////////////////////// - -// LLVM coding style -#define INDENT_LEVEL 2 - -/// Indenter - A little helper class to keep track of the indentation depth, -/// while the instance object is being passed around. -class Indenter { -public: - Indenter() : depth(0) {} - - void push() { - depth += INDENT_LEVEL; - } - - void pop() { - if (depth >= INDENT_LEVEL) - depth -= INDENT_LEVEL; - } - - // Conversion operator. - operator int () { - return depth; - } -private: - uint8_t depth; -}; - -///////////////////////// -// Utility functions // -///////////////////////// - -static uint8_t byteFromBitsInit(BitsInit &init) { - int width = init.getNumBits(); - - assert(width <= 8 && "Field is too large for uint8_t!"); - - int index; - uint8_t mask = 0x01; - - uint8_t ret = 0; - - for (index = 0; index < width; index++) { - if (static_cast(init.getBit(index))->getValue()) - ret |= mask; - - mask <<= 1; - } - - return ret; -} - -static uint8_t getByteField(const Record &def, const char *str) { - BitsInit *bits = def.getValueAsBitsInit(str); - return byteFromBitsInit(*bits); -} - -static BitsInit &getBitsField(const Record &def, const char *str) { - BitsInit *bits = def.getValueAsBitsInit(str); - return *bits; -} - -/// sameStringExceptEndingChar - Return true if the two strings differ only in -/// the ending char. ("VST4q8a", "VST4q8b", 'a', 'b') as input returns true. -static -bool sameStringExceptEndingChar(const std::string &LHS, const std::string &RHS, - char lhc, char rhc) { - - if (LHS.length() > 1 && RHS.length() > 1 && LHS.length() == RHS.length()) { - unsigned length = LHS.length(); - return LHS.substr(0, length - 1) == RHS.substr(0, length - 1) - && LHS[length - 1] == lhc && RHS[length - 1] == rhc; - } - - return false; -} - -/// thumbInstruction - Determine whether we have a Thumb instruction. -/// See also ARMInstrFormats.td. -static bool thumbInstruction(uint8_t Form) { - return Form == 23; -} - -// The set (BIT_TRUE, BIT_FALSE, BIT_UNSET) represents a ternary logic system -// for a bit value. -// -// BIT_UNFILTERED is used as the init value for a filter position. It is used -// only for filter processings. -typedef enum { - BIT_TRUE, // '1' - BIT_FALSE, // '0' - BIT_UNSET, // '?' - BIT_UNFILTERED // unfiltered -} bit_value_t; - -static bit_value_t bitFromBits(BitsInit &bits, unsigned index) { - if (BitInit *bit = dynamic_cast(bits.getBit(index))) - return bit->getValue() ? BIT_TRUE : BIT_FALSE; - - // The bit is uninitialized. - return BIT_UNSET; -} - -static void dumpBits(raw_ostream &o, BitsInit &bits) { - unsigned index; - - for (index = bits.getNumBits(); index > 0; index--) { - switch (bitFromBits(bits, index - 1)) { - case BIT_TRUE: - o << "1"; - break; - case BIT_FALSE: - o << "0"; - break; - case BIT_UNSET: - o << "_"; - break; - default: - assert(0 && "unexpected return value from bitFromBits"); - } - } -} - -///////////// -// Enums // -///////////// - -#define ARM_FORMATS \ - ENTRY(ARM_FORMAT_PSEUDO, 0) \ - ENTRY(ARM_FORMAT_MULFRM, 1) \ - ENTRY(ARM_FORMAT_BRFRM, 2) \ - ENTRY(ARM_FORMAT_BRMISCFRM, 3) \ - ENTRY(ARM_FORMAT_DPFRM, 4) \ - ENTRY(ARM_FORMAT_DPSOREGFRM, 5) \ - ENTRY(ARM_FORMAT_LDFRM, 6) \ - ENTRY(ARM_FORMAT_STFRM, 7) \ - ENTRY(ARM_FORMAT_LDMISCFRM, 8) \ - ENTRY(ARM_FORMAT_STMISCFRM, 9) \ - ENTRY(ARM_FORMAT_LDSTMULFRM, 10) \ - ENTRY(ARM_FORMAT_ARITHMISCFRM, 11) \ - ENTRY(ARM_FORMAT_EXTFRM, 12) \ - ENTRY(ARM_FORMAT_VFPUNARYFRM, 13) \ - ENTRY(ARM_FORMAT_VFPBINARYFRM, 14) \ - ENTRY(ARM_FORMAT_VFPCONV1FRM, 15) \ - ENTRY(ARM_FORMAT_VFPCONV2FRM, 16) \ - ENTRY(ARM_FORMAT_VFPCONV3FRM, 17) \ - ENTRY(ARM_FORMAT_VFPCONV4FRM, 18) \ - ENTRY(ARM_FORMAT_VFPCONV5FRM, 19) \ - ENTRY(ARM_FORMAT_VFPLDSTFRM, 20) \ - ENTRY(ARM_FORMAT_VFPLDSTMULFRM, 21) \ - ENTRY(ARM_FORMAT_VFPMISCFRM, 22) \ - ENTRY(ARM_FORMAT_THUMBFRM, 23) \ - ENTRY(ARM_FORMAT_NEONFRM, 24) \ - ENTRY(ARM_FORMAT_NEONGETLNFRM, 25) \ - ENTRY(ARM_FORMAT_NEONSETLNFRM, 26) \ - ENTRY(ARM_FORMAT_NEONDUPFRM, 27) \ - ENTRY(ARM_FORMAT_LDSTEXFRM, 28) \ - ENTRY(ARM_FORMAT_MISCFRM, 29) \ - ENTRY(ARM_FORMAT_THUMBMISCFRM, 30) - -// ARM instruction format specifies the encoding used by the instruction. -#define ENTRY(n, v) n = v, -typedef enum { - ARM_FORMATS - ARM_FORMAT_NA -} ARMFormat; -#undef ENTRY - -// Converts enum to const char*. -static const char *stringForARMFormat(ARMFormat form) { -#define ENTRY(n, v) case n: return #n; - switch(form) { - ARM_FORMATS - case ARM_FORMAT_NA: - default: - return ""; - } -#undef ENTRY -} - -#define NS_FORMATS \ - ENTRY(NS_FORMAT_NONE, 0) \ - ENTRY(NS_FORMAT_VLDSTLane, 1) \ - ENTRY(NS_FORMAT_VLDSTLaneDbl, 2) \ - ENTRY(NS_FORMAT_VLDSTRQ, 3) \ - ENTRY(NS_FORMAT_NVdImm, 4) \ - ENTRY(NS_FORMAT_NVdVmImm, 5) \ - ENTRY(NS_FORMAT_NVdVmImmVCVT, 6) \ - ENTRY(NS_FORMAT_NVdVmImmVDupLane, 7) \ - ENTRY(NS_FORMAT_NVdVmImmVSHLL, 8) \ - ENTRY(NS_FORMAT_NVectorShuffle, 9) \ - ENTRY(NS_FORMAT_NVectorShift, 10) \ - ENTRY(NS_FORMAT_NVectorShift2, 11) \ - ENTRY(NS_FORMAT_NVdVnVmImm, 12) \ - ENTRY(NS_FORMAT_NVdVnVmImmVectorShift, 13) \ - ENTRY(NS_FORMAT_NVdVnVmImmVectorExtract, 14) \ - ENTRY(NS_FORMAT_NVdVnVmImmMulScalar, 15) \ - ENTRY(NS_FORMAT_VTBL, 16) - -// NEON instruction sub-format further classify the NEONFrm instruction. -#define ENTRY(n, v) n = v, -typedef enum { - NS_FORMATS - NS_FORMAT_NA -} NSFormat; -#undef ENTRY - -// Converts enum to const char*. -static const char *stringForNSFormat(NSFormat form) { -#define ENTRY(n, v) case n: return #n; - switch(form) { - NS_FORMATS - case NS_FORMAT_NA: - default: - return ""; - } -#undef ENTRY -} - -// Enums for the available target names. -typedef enum { - TARGET_ARM = 0, - TARGET_THUMB -} TARGET_NAME_t; - -class AbstractFilterChooser { -public: - static TARGET_NAME_t TargetName; - static void setTargetName(TARGET_NAME_t tn) { TargetName = tn; } - virtual ~AbstractFilterChooser() {} - virtual void emitTop(raw_ostream &o, Indenter &i) = 0; - virtual void emitBot(raw_ostream &o, Indenter &i) = 0; -}; - -// Define the symbol here. -TARGET_NAME_t AbstractFilterChooser::TargetName; - -template -class FilterChooser : public AbstractFilterChooser { -protected: - // Representation of the instruction to work on. - typedef bit_value_t insn_t[tBitWidth]; - - class Filter { - protected: - FilterChooser *Owner; // pointer without ownership - unsigned StartBit; // the starting bit position - unsigned NumBits; // number of bits to filter - bool Mixed; // a mixed region contains both set and unset bits - - // Map of well-known segment value to the set of uid's with that value. - std::map > FilteredInstructions; - - // Set of uid's with non-constant segment values. - std::vector VariableInstructions; - - // Map of well-known segment value to its delegate. - std::map FilterChooserMap; - - // Number of instructions which fall under FilteredInstructions category. - unsigned NumFiltered; - - // Keeps track of the last opcode in the filtered bucket. - unsigned LastOpcFiltered; - - // Number of instructions which fall under VariableInstructions category. - unsigned NumVariable; - - public: - unsigned getNumFiltered() { return NumFiltered; } - unsigned getNumVariable() { return NumVariable; } - unsigned getSingletonOpc() { - assert(NumFiltered == 1); - return LastOpcFiltered; - } - FilterChooser &getVariableFC() { - assert(NumFiltered == 1); - assert(FilterChooserMap.size() == 1); - return FilterChooserMap.find(-1)->second; - } - - Filter(const Filter &f) : - Owner(f.Owner), - StartBit(f.StartBit), - NumBits(f.NumBits), - Mixed(f.Mixed), - FilteredInstructions(f.FilteredInstructions), - VariableInstructions(f.VariableInstructions), - FilterChooserMap(f.FilterChooserMap), - NumFiltered(f.NumFiltered), - LastOpcFiltered(f.LastOpcFiltered), - NumVariable(f.NumVariable) { } - - Filter(FilterChooser &owner, unsigned startBit, unsigned numBits, - bool mixed) : - Owner(&owner), - StartBit(startBit), - NumBits(numBits), - Mixed(mixed) - { - assert(StartBit + NumBits - 1 < tBitWidth); - - NumFiltered = 0; - LastOpcFiltered = 0; - NumVariable = 0; - - for (unsigned i = 0, e = Owner->Opcodes.size(); i != e; ++i) { - insn_t Insn; - - // Populates the insn given the uid. - Owner->insnWithID(Insn, Owner->Opcodes[i]); - - uint64_t Field; - // Scans the segment for possibly well-specified encoding bits. - bool ok = Owner->fieldFromInsn(Field, Insn, StartBit, NumBits); - - if (ok) { - // The encoding bits are well-known. Lets add the uid of the - // instruction into the bucket keyed off the constant field value. - LastOpcFiltered = Owner->Opcodes[i]; - FilteredInstructions[Field].push_back(LastOpcFiltered); - ++NumFiltered; - } else { - // Some of the encoding bit(s) are unspecfied. This contributes to - // one additional member of "Variable" instructions. - VariableInstructions.push_back(Owner->Opcodes[i]); - ++NumVariable; - } - } - - assert((FilteredInstructions.size() + VariableInstructions.size() > 0) - && "Filter returns no instruction categories"); - } - - // Divides the decoding task into sub tasks and delegates them to the - // inferior FilterChooser's. - // - // A special case arises when there's only one entry in the filtered - // instructions. In order to unambiguously decode the singleton, we need to - // match the remaining undecoded encoding bits against the singleton. - void recurse() { - std::map >::const_iterator mapIterator; - - bit_value_t BitValueArray[tBitWidth]; - // Starts by inheriting our parent filter chooser's filter bit values. - memcpy(BitValueArray, Owner->FilterBitValues, sizeof(BitValueArray)); - - unsigned bitIndex; - - if (VariableInstructions.size()) { - // Conservatively marks each segment position as BIT_UNSET. - for (bitIndex = 0; bitIndex < NumBits; bitIndex++) - BitValueArray[StartBit + bitIndex] = BIT_UNSET; - - // Delegates to an inferior filter chooser for futher processing on this - // group of instructions whose segment values are variable. - FilterChooserMap.insert(std::pair( - (unsigned)-1, - FilterChooser(Owner->AllInstructions, - VariableInstructions, - BitValueArray, - *Owner) - )); - } - - // No need to recurse for a singleton filtered instruction. - // See also Filter::emit(). - if (getNumFiltered() == 1) { - //Owner->SingletonExists(LastOpcFiltered); - assert(FilterChooserMap.size() == 1); - return; - } - - // Otherwise, create sub choosers. - for (mapIterator = FilteredInstructions.begin(); - mapIterator != FilteredInstructions.end(); - mapIterator++) { - - // Marks all the segment positions with either BIT_TRUE or BIT_FALSE. - for (bitIndex = 0; bitIndex < NumBits; bitIndex++) { - if (mapIterator->first & (1 << bitIndex)) - BitValueArray[StartBit + bitIndex] = BIT_TRUE; - else - BitValueArray[StartBit + bitIndex] = BIT_FALSE; - } - - // Delegates to an inferior filter chooser for futher processing on this - // category of instructions. - FilterChooserMap.insert(std::pair( - mapIterator->first, - FilterChooser(Owner->AllInstructions, - mapIterator->second, - BitValueArray, - *Owner) - )); - } - } - - // Emit code to decode instructions given a segment or segments of bits. - void emit(raw_ostream &o, Indenter &i) { - o.indent(i) << "// Check Inst{"; - - if (NumBits > 1) - o << (StartBit + NumBits - 1) << '-'; - - o << StartBit << "} ...\n"; - - o.indent(i) << "switch (fieldFromInstruction(insn, " - << StartBit << ", " << NumBits << ")) {\n"; - - typename std::map::iterator filterIterator; - - bool DefaultCase = false; - for (filterIterator = FilterChooserMap.begin(); - filterIterator != FilterChooserMap.end(); - filterIterator++) { - - // Field value -1 implies a non-empty set of variable instructions. - // See also recurse(). - if (filterIterator->first == (unsigned)-1) { - DefaultCase = true; - - o.indent(i) << "default:\n"; - o.indent(i) << " break; // fallthrough\n"; - - // Closing curly brace for the switch statement. - // This is unconventional because we want the default processing to be - // performed for the fallthrough cases as well, i.e., when the "cases" - // did not prove a decoded instruction. - o.indent(i) << "}\n"; - - } else { - o.indent(i) << "case " << filterIterator->first << ":\n"; - } - - // We arrive at a category of instructions with the same segment value. - // Now delegate to the sub filter chooser for further decodings. - // The case may fallthrough, which happens if the remaining well-known - // encoding bits do not match exactly. - if (!DefaultCase) i.push(); - { - bool finished = filterIterator->second.emit(o, i); - // For top level default case, there's no need for a break statement. - if (Owner->isTopLevel() && DefaultCase) - break; - if (!finished) - o.indent(i) << "break;\n"; - } - if (!DefaultCase) i.pop(); - } - - // If there is no default case, we still need to supply a closing brace. - if (!DefaultCase) { - // Closing curly brace for the switch statement. - o.indent(i) << "}\n"; - } - } - - // Returns the number of fanout produced by the filter. More fanout implies - // the filter distinguishes more categories of instructions. - unsigned usefulness() const { - if (VariableInstructions.size()) - return FilteredInstructions.size(); - else - return FilteredInstructions.size() + 1; - } - }; // End of inner class Filter - - friend class Filter; - - // Vector of codegen instructions to choose our filter. - const std::vector &AllInstructions; - - // Vector of uid's for this filter chooser to work on. - const std::vector Opcodes; - - // Vector of candidate filters. - std::vector Filters; - - // Array of bit values passed down from our parent. - // Set to all BIT_UNFILTERED's for Parent == NULL. - bit_value_t FilterBitValues[tBitWidth]; - - // Links to the FilterChooser above us in the decoding tree. - FilterChooser *Parent; - - // Index of the best filter from Filters. - int BestIndex; - -public: - FilterChooser(const FilterChooser &FC) : - AbstractFilterChooser(), - AllInstructions(FC.AllInstructions), - Opcodes(FC.Opcodes), - Filters(FC.Filters), - Parent(FC.Parent), - BestIndex(FC.BestIndex) - { - memcpy(FilterBitValues, FC.FilterBitValues, sizeof(FilterBitValues)); - } - - FilterChooser(const std::vector &Insts, - const std::vector &IDs) : - AllInstructions(Insts), - Opcodes(IDs), - Filters(), - Parent(NULL), - BestIndex(-1) - { - for (unsigned i = 0; i < tBitWidth; ++i) - FilterBitValues[i] = BIT_UNFILTERED; - - doFilter(); - } - - FilterChooser(const std::vector &Insts, - const std::vector &IDs, - bit_value_t (&ParentFilterBitValues)[tBitWidth], - FilterChooser &parent) : - AllInstructions(Insts), - Opcodes(IDs), - Filters(), - Parent(&parent), - BestIndex(-1) - { - for (unsigned i = 0; i < tBitWidth; ++i) - FilterBitValues[i] = ParentFilterBitValues[i]; - - doFilter(); - } - - // The top level filter chooser has NULL as its parent. - bool isTopLevel() { return Parent == NULL; } - - // This provides an opportunity for target specific code emission. - void emitTopHook(raw_ostream &o, Indenter &i) { - if (TargetName == TARGET_ARM) { - // Emit code that references the ARMFormat data type. - o << "static const ARMFormat ARMFormats[] = {\n"; - for (unsigned i = 0, e = AllInstructions.size(); i != e; ++i) { - const Record &Def = *(AllInstructions[i]->TheDef); - const std::string &Name = Def.getName(); - if (Def.isSubClassOf("InstARM") || Def.isSubClassOf("InstThumb")) - o.indent(2) << - stringForARMFormat((ARMFormat)getByteField(Def, "Form")); - else - o << " ARM_FORMAT_NA"; - - o << ",\t// Inst #" << i << " = " << Name << '\n'; - } - o << " ARM_FORMAT_NA\t// Unreachable.\n"; - o << "};\n\n"; - - // And emit code that references the NSFormat data type. - // This is meaningful only for NEONFrm instructions. - o << "static const NSFormat NSFormats[] = {\n"; - for (unsigned i = 0, e = AllInstructions.size(); i != e; ++i) { - const Record &Def = *(AllInstructions[i]->TheDef); - const std::string &Name = Def.getName(); - if (Def.isSubClassOf("NeonI") || Def.isSubClassOf("NeonXI")) - o.indent(2) << - stringForNSFormat((NSFormat)getByteField(Def, "NSForm")); - else - o << " NS_FORMAT_NA"; - - o << ",\t// Inst #" << i << " = " << Name << '\n'; - } - o << " NS_FORMAT_NA\t// Unreachable.\n"; - o << "};\n\n"; - } - } - - // Emit the top level typedef and decodeInstruction() function. - void emitTop(raw_ostream &o, Indenter &i) { - - // Run the target specific emit hook. - emitTopHook(o, i); - - switch(tBitWidth) { - case 8: - o.indent(i) << "typedef uint8_t field_t;\n"; - break; - case 16: - o.indent(i) << "typedef uint16_t field_t;\n"; - break; - case 32: - o.indent(i) << "typedef uint32_t field_t;\n"; - break; - case 64: - o.indent(i) << "typedef uint64_t field_t;\n"; - break; - default: - assert(0 && "Unexpected instruction size!"); - } - - o << '\n'; - - o.indent(i) << "static field_t " << - "fieldFromInstruction(field_t insn, unsigned startBit, unsigned numBits)\n"; - - o.indent(i) << "{\n"; - i.push(); - { - o.indent(i) << "assert(startBit + numBits <= " << tBitWidth - << " && \"Instruction field out of bounds!\");\n"; - o << '\n'; - o.indent(i) << "field_t fieldMask;\n"; - o << '\n'; - o.indent(i) << "if (numBits == " << tBitWidth << ")\n"; - - i.push(); - { - o.indent(i) << "fieldMask = (field_t)-1;\n"; - } - i.pop(); - - o.indent(i) << "else\n"; - - i.push(); - { - o.indent(i) << "fieldMask = ((1 << numBits) - 1) << startBit;\n"; - } - i.pop(); - - o << '\n'; - o.indent(i) << "return (insn & fieldMask) >> startBit;\n"; - } - i.pop(); - o.indent(i) << "}\n"; - - o << '\n'; - - o.indent(i) << "static uint16_t decodeInstruction(field_t insn) {\n"; - - i.push(); - { - // Emits code to decode the instructions. - emit(o, i); - - o << '\n'; - o.indent(i) << "return 0;\n"; - } - i.pop(); - - o.indent(i) << "}\n"; - - o << '\n'; - - } - - // This provides an opportunity for target specific code emission after - // emitTop(). - void emitBot(raw_ostream &o, Indenter &i) { - if (TargetName == TARGET_THUMB) { - // Emit code that decodes the Thumb ISA. - o.indent(i) - << "static uint16_t decodeThumbInstruction(field_t insn) {\n"; - - i.push(); - { - // Emits code to decode the instructions. - emit(o, i); - - o << '\n'; - o.indent(i) << "return 0;\n"; - } - i.pop(); - - o.indent(i) << "}\n"; - } - } - -protected: - // Populates the insn given the uid. - void insnWithID(insn_t &Insn, unsigned Opcode) const { - assert(Opcode > 10); - BitsInit &Bits = getBitsField(*AllInstructions[Opcode]->TheDef, "Inst"); - - for (unsigned i = 0; i < tBitWidth; ++i) - Insn[i] = bitFromBits(Bits, i); - } - - // Returns the record name. - const std::string &nameWithID(unsigned Opcode) const { - return AllInstructions[Opcode]->TheDef->getName(); - } - - // Populates the field of the insn given the start position and the number of - // consecutive bits to scan for. - // - // Returns false if and on the first uninitialized bit value encountered. - // Returns true, otherwise. - const bool fieldFromInsn(uint64_t &Field, insn_t &Insn, unsigned StartBit, - unsigned NumBits) const { - Field = 0; - - for (unsigned i = 0; i < NumBits; ++i) { - if (Insn[StartBit + i] == BIT_UNSET) - return false; - - if (Insn[StartBit + i] == BIT_TRUE) - Field = Field | (1 << i); - } - - return true; - } - - void dumpFilterArray(raw_ostream &o, bit_value_t (&filter)[tBitWidth]) { - unsigned bitIndex; - - for (bitIndex = tBitWidth; bitIndex > 0; bitIndex--) { - switch (filter[bitIndex - 1]) { - case BIT_UNFILTERED: - o << "."; - break; - case BIT_UNSET: - o << "_"; - break; - case BIT_TRUE: - o << "1"; - break; - case BIT_FALSE: - o << "0"; - break; - } - } - } - - void dumpStack(raw_ostream &o, const char *prefix) { - FilterChooser *current = this; - - while (current) { - o << prefix; - - dumpFilterArray(o, current->FilterBitValues); - - o << '\n'; - - current = current->Parent; - } - } - - Filter &bestFilter() { - assert(BestIndex != -1 && "BestIndex not set"); - return Filters[BestIndex]; - } - - // States of our finite state machines. - typedef enum { - ATTR_NONE, - ATTR_FILTERED, - ATTR_ALL_SET, - ATTR_ALL_UNSET, - ATTR_MIXED - } bitAttr_t; - - // Called from Filter::recurse() when singleton exists. For debug purpose. - void SingletonExists(unsigned Opc) { - - insn_t Insn0; - insnWithID(Insn0, Opc); - - errs() << "Singleton exists: " << nameWithID(Opc) - << " with its decoding dominating "; - for (unsigned i = 0; i < Opcodes.size(); ++i) { - if (Opcodes[i] == Opc) continue; - errs() << nameWithID(Opcodes[i]) << ' '; - } - errs() << '\n'; - - dumpStack(errs(), "\t\t"); - for (unsigned i = 0; i < Opcodes.size(); i++) { - const std::string &Name = nameWithID(Opcodes[i]); - - errs() << '\t' << Name << " "; - dumpBits(errs(), - getBitsField(*AllInstructions[Opcodes[i]]->TheDef, "Inst")); - errs() << '\n'; - } - } - - bool ValueSet(bit_value_t V) { - return (V == BIT_TRUE || V == BIT_FALSE); - } - bool ValueNotSet(bit_value_t V) { - return (V == BIT_UNSET); - } - int Value(bit_value_t V) { - return ValueNotSet(V) ? -1 : (V == BIT_FALSE ? 0 : 1); - } - bool PositionFiltered(unsigned i) { - return ValueSet(FilterBitValues[i]); - } - - // Calculates the island(s) needed to decode the instruction. - unsigned getIslands(std::vector &StartBits, - std::vector &EndBits, - std::vector &FieldVals, insn_t &Insn) - { - unsigned Num, BitNo; - Num = BitNo = 0; - - uint64_t FieldVal = 0; - - // 0: Init - // 1: Water - // 2: Island - int State = 0; - int Val = -1; - - for (unsigned i = 0; i < tBitWidth; ++i) { - Val = Value(Insn[i]); - bool Filtered = PositionFiltered(i); - switch (State) { - default: - assert(0 && "Unreachable code!"); - break; - case 0: - case 1: - if (Filtered || Val == -1) - State = 1; // Still in Water - else { - State = 2; // Into the Island - BitNo = 0; - StartBits.push_back(i); - FieldVal = Val; - } - break; - case 2: - if (Filtered || Val == -1) { - State = 1; // Into the Water - EndBits.push_back(i - 1); - FieldVals.push_back(FieldVal); - ++Num; - } else { - State = 2; // Still in Island - ++BitNo; - FieldVal = FieldVal | Val << BitNo; - } - break; - } - } - // If we are still in Island after the loop, do some housekeeping. - if (State == 2) { - EndBits.push_back(tBitWidth - 1); - FieldVals.push_back(FieldVal); - ++Num; - } - - /* - printf("StartBits.size()=%u,EndBits.size()=%u,FieldVals.size()=%u,Num=%u\n", - (unsigned)StartBits.size(), (unsigned)EndBits.size(), - (unsigned)FieldVals.size(), Num); - */ - - assert(StartBits.size() == Num && EndBits.size() == Num && - FieldVals.size() == Num); - - return Num; - } - - bool LdStCopEncoding1(unsigned Opc) { - const std::string &Name = nameWithID(Opc); - if (Name == "LDC_OFFSET" || Name == "LDC_OPTION" || - Name == "LDC_POST" || Name == "LDC_PRE" || - Name == "LDCL_OFFSET" || Name == "LDCL_OPTION" || - Name == "LDCL_POST" || Name == "LDCL_PRE" || - Name == "STC_OFFSET" || Name == "STC_OPTION" || - Name == "STC_POST" || Name == "STC_PRE" || - Name == "STCL_OFFSET" || Name == "STCL_OPTION" || - Name == "STCL_POST" || Name == "STCL_PRE") - return true; - else - return false; - } - - // Emits code to decode the singleton. Return true if we have matched all the - // well-known bits. - bool emitSingletonDecoder(raw_ostream &o, Indenter &i, unsigned Opc) { - - std::vector StartBits; - std::vector EndBits; - std::vector FieldVals; - insn_t Insn; - insnWithID(Insn, Opc); - - if (TargetName == TARGET_ARM && LdStCopEncoding1(Opc)) { - o.indent(i); - // A8.6.51 & A8.6.188 - // If coproc = 0b101?, i.e, slice(insn, 11, 8) = 10 or 11, escape. - o << "if (fieldFromInstruction(insn, 9, 3) == 5) break; // fallthrough\n"; - } - - // Look for islands of undecoded bits of the singleton. - getIslands(StartBits, EndBits, FieldVals, Insn); - - unsigned Size = StartBits.size(); - unsigned I, NumBits; - - // If we have matched all the well-known bits, just issue a return. - if (Size == 0) { - o.indent(i) << "return " << Opc << "; // " << nameWithID(Opc) << '\n'; - return true; - } - - // Otherwise, there are more decodings to be done! - - // Emit code to match the island(s) for the singleton. - o.indent(i) << "// Check "; - - for (I = Size; I != 0; --I) { - o << "Inst{" << EndBits[I-1] << '-' << StartBits[I-1] << "} "; - if (I > 1) - o << "&& "; - else - o << "for singleton decoding...\n"; - } - - o.indent(i) << "if ("; - - for (I = Size; I != 0; --I) { - NumBits = EndBits[I-1] - StartBits[I-1] + 1; - o << "fieldFromInstruction(insn, " << StartBits[I-1] << ", " << NumBits - << ") == " << FieldVals[I-1]; - if (I > 1) - o << " && "; - else - o << ")\n"; - } - - o.indent(i) << " return " << Opc << "; // " << nameWithID(Opc) << '\n'; - - return false; - } - - // Emits code to decode the singleton, and then to decode the rest. - void emitSingletonDecoder(raw_ostream &o, Indenter &i, Filter & Best) { - - unsigned Opc = Best.getSingletonOpc(); - - emitSingletonDecoder(o, i, Opc); - - // Emit code for the rest. - o.indent(i) << "else\n"; - i.push(); - { - Best.getVariableFC().emit(o, i); - } - i.pop(); - } - - // Assign a single filter and run with it. - void runSingleFilter(FilterChooser &owner, unsigned startBit, unsigned numBit, - bool mixed) { - Filters.clear(); - Filter F(*this, startBit, numBit, true); - Filters.push_back(F); - BestIndex = 0; // Sole Filter instance to choose from. - bestFilter().recurse(); - } - - bool filterProcessor(bool AllowMixed, bool Greedy = true) { - Filters.clear(); - BestIndex = -1; - unsigned numInstructions = Opcodes.size(); - - assert(numInstructions && "Filter created with no instructions"); - - // No further filtering is necessary. - if (numInstructions == 1) - return true; - - // Heuristics. See also doFilter()'s "Heuristics" comment when num of - // instructions is 3. - if (AllowMixed && !Greedy) { - assert(numInstructions == 3); - - for (unsigned i = 0; i < Opcodes.size(); ++i) { - std::vector StartBits; - std::vector EndBits; - std::vector FieldVals; - insn_t Insn; - - insnWithID(Insn, Opcodes[i]); - - // Look for islands of undecoded bits of any instruction. - if (getIslands(StartBits, EndBits, FieldVals, Insn) > 0) { - // Found an instruction with island(s). Now just assign a filter. - runSingleFilter(*this, StartBits[0], EndBits[0] - StartBits[0] + 1, - true); - return true; - } - } - } - - unsigned bitIndex, insnIndex; - - // We maintain tBitWidth copies of the bitAttrs automaton. - // The automaton consumes the corresponding bit from each - // instruction. - // - // Input symbols: 0, 1, and _ (unset). - // States: NONE, FILTERED, ALL_SET, ALL_UNSET, and MIXED. - // Initial state: NONE. - // - // (NONE) ------- [01] -> (ALL_SET) - // (NONE) ------- _ ----> (ALL_UNSET) - // (ALL_SET) ---- [01] -> (ALL_SET) - // (ALL_SET) ---- _ ----> (MIXED) - // (ALL_UNSET) -- [01] -> (MIXED) - // (ALL_UNSET) -- _ ----> (ALL_UNSET) - // (MIXED) ------ . ----> (MIXED) - // (FILTERED)---- . ----> (FILTERED) - - bitAttr_t bitAttrs[tBitWidth]; - - // FILTERED bit positions provide no entropy and are not worthy of pursuing. - // Filter::recurse() set either BIT_TRUE or BIT_FALSE for each position. - for (bitIndex = 0; bitIndex < tBitWidth; ++bitIndex) - if (FilterBitValues[bitIndex] == BIT_TRUE || - FilterBitValues[bitIndex] == BIT_FALSE) - bitAttrs[bitIndex] = ATTR_FILTERED; - else - bitAttrs[bitIndex] = ATTR_NONE; - - for (insnIndex = 0; insnIndex < numInstructions; ++insnIndex) { - insn_t insn; - - insnWithID(insn, Opcodes[insnIndex]); - - for (bitIndex = 0; bitIndex < tBitWidth; ++bitIndex) { - switch (bitAttrs[bitIndex]) { - case ATTR_NONE: - if (insn[bitIndex] == BIT_UNSET) - bitAttrs[bitIndex] = ATTR_ALL_UNSET; - else - bitAttrs[bitIndex] = ATTR_ALL_SET; - break; - case ATTR_ALL_SET: - if (insn[bitIndex] == BIT_UNSET) - bitAttrs[bitIndex] = ATTR_MIXED; - break; - case ATTR_ALL_UNSET: - if (insn[bitIndex] != BIT_UNSET) - bitAttrs[bitIndex] = ATTR_MIXED; - break; - case ATTR_MIXED: - case ATTR_FILTERED: - break; - } - } - } - - // The regionAttr automaton consumes the bitAttrs automatons' state, - // lowest-to-highest. - // - // Input symbols: F(iltered), (all_)S(et), (all_)U(nset), M(ixed) - // States: NONE, ALL_SET, MIXED - // Initial state: NONE - // - // (NONE) ----- F --> (NONE) - // (NONE) ----- S --> (ALL_SET) ; and set region start - // (NONE) ----- U --> (NONE) - // (NONE) ----- M --> (MIXED) ; and set region start - // (ALL_SET) -- F --> (NONE) ; and report an ALL_SET region - // (ALL_SET) -- S --> (ALL_SET) - // (ALL_SET) -- U --> (NONE) ; and report an ALL_SET region - // (ALL_SET) -- M --> (MIXED) ; and report an ALL_SET region - // (MIXED) ---- F --> (NONE) ; and report a MIXED region - // (MIXED) ---- S --> (ALL_SET) ; and report a MIXED region - // (MIXED) ---- U --> (NONE) ; and report a MIXED region - // (MIXED) ---- M --> (MIXED) - - bitAttr_t regionAttr = ATTR_NONE; - unsigned startBit = 0; - - for (bitIndex = 0; bitIndex < tBitWidth; bitIndex++) { - bitAttr_t bitAttr = bitAttrs[bitIndex]; - - assert(bitAttr != ATTR_NONE && "Bit without attributes"); - -#define SET_START \ - startBit = bitIndex; - -#define REPORT_REGION \ - if (regionAttr == ATTR_MIXED && AllowMixed) \ - Filters.push_back(Filter(*this, startBit, bitIndex - startBit, true)); \ - else if (regionAttr == ATTR_ALL_SET && !AllowMixed) \ - Filters.push_back(Filter(*this, startBit, bitIndex - startBit, false)); - - switch (regionAttr) { - case ATTR_NONE: - switch (bitAttr) { - case ATTR_FILTERED: - break; - case ATTR_ALL_SET: - SET_START - regionAttr = ATTR_ALL_SET; - break; - case ATTR_ALL_UNSET: - break; - case ATTR_MIXED: - SET_START - regionAttr = ATTR_MIXED; - break; - default: - assert(0 && "Unexpected bitAttr!"); - } - break; - case ATTR_ALL_SET: - switch (bitAttr) { - case ATTR_FILTERED: - REPORT_REGION - regionAttr = ATTR_NONE; - break; - case ATTR_ALL_SET: - break; - case ATTR_ALL_UNSET: - REPORT_REGION - regionAttr = ATTR_NONE; - break; - case ATTR_MIXED: - REPORT_REGION - SET_START - regionAttr = ATTR_MIXED; - break; - default: - assert(0 && "Unexpected bitAttr!"); - } - break; - case ATTR_MIXED: - switch (bitAttr) { - case ATTR_FILTERED: - REPORT_REGION - SET_START - regionAttr = ATTR_NONE; - break; - case ATTR_ALL_SET: - REPORT_REGION - SET_START - regionAttr = ATTR_ALL_SET; - break; - case ATTR_ALL_UNSET: - REPORT_REGION - regionAttr = ATTR_NONE; - break; - case ATTR_MIXED: - break; - default: - assert(0 && "Unexpected bitAttr!"); - } - break; - case ATTR_ALL_UNSET: - assert(0 && "regionAttr state machine has no ATTR_UNSET state"); - case ATTR_FILTERED: - assert(0 && "regionAttr state machine has no ATTR_FILTERED state"); - } - } - - // At the end, if we're still in ALL_SET or MIXED states, report a region - - switch (regionAttr) { - case ATTR_NONE: - break; - case ATTR_FILTERED: - break; - case ATTR_ALL_SET: - REPORT_REGION - break; - case ATTR_ALL_UNSET: - break; - case ATTR_MIXED: - REPORT_REGION - break; - } - -#undef SET_START -#undef REPORT_REGION - - // We have finished with the filter processings. Now it's time to choose - // the best performing filter. - - BestIndex = 0; - bool AllUseless = true; - unsigned BestScore = 0; - - for (unsigned i = 0, e = Filters.size(); i != e; ++i) { - unsigned Usefulness = Filters[i].usefulness(); - - if (Usefulness) - AllUseless = false; - - if (Usefulness > BestScore) { - BestIndex = i; - BestScore = Usefulness; - } - } - - if (!AllUseless) { - bestFilter().recurse(); - } - - return !AllUseless; - } // end of filterProcessor(bool) - - // Decides on the best configuration of filter(s) to use in order to decode - // the instructions. A conflict of instructions may occur, in which case we - // dump the conflict set to the standard error. - void doFilter() { - unsigned Num = Opcodes.size(); - assert(Num && "FilterChooser created with no instructions"); - - // Heuristics: Use Inst{31-28} as the top level filter for ARM ISA. - if (TargetName == TARGET_ARM && Parent == NULL) { - runSingleFilter(*this, 28, 4, false); - return; - } - - if (filterProcessor(false)) - return; - - if (filterProcessor(true)) - return; - - // Heuristics to cope with conflict set {t2CMPrs, t2SUBSrr, t2SUBSrs} where - // no single instruction for the maximum ATTR_MIXED region Inst{14-4} has a - // well-known encoding pattern. In such case, we backtrack and scan for the - // the very first consecutive ATTR_ALL_SET region and assign a filter to it. - if (Num == 3 && filterProcessor(true, false)) - return; - - // If we come to here, the instruction decoding has failed. - // Print out the instructions in the conflict set... - - BestIndex = -1; - - DEBUG({ - errs() << "Conflict:\n"; - - dumpStack(errs(), "\t\t"); - - for (unsigned i = 0; i < Num; i++) { - const std::string &Name = nameWithID(Opcodes[i]); - - errs() << '\t' << Name << " "; - dumpBits(errs(), - getBitsField(*AllInstructions[Opcodes[i]]->TheDef, "Inst")); - errs() << '\n'; - } - }); - } - - // Emits code to decode our share of instructions. Returns true if the - // emitted code causes a return, which occurs if we know how to decode - // the instruction at this level or the instruction is not decodeable. - bool emit(raw_ostream &o, Indenter &i) { - if (Opcodes.size() == 1) { - // There is only one instruction in the set, which is great! - // Call emitSingletonDecoder() to see whether there are any remaining - // encodings bits. - return emitSingletonDecoder(o, i, Opcodes[0]); - - } else if (BestIndex == -1) { - if (TargetName == TARGET_ARM && Opcodes.size() == 2) { - // Resolve the known conflict sets: - // - // 1. source registers are identical => VMOVDneon; otherwise => VORRd - // 2. source registers are identical => VMOVQ; otherwise => VORRq - // 3. LDR, LDRcp => return LDR for now. - // FIXME: How can we distinguish between LDR and LDRcp? Do we need to? - // 4. VLD[234]LN*a/VST[234]LN*a vs. VLD[234]LN*b/VST[234]LN*b conflicts - // are resolved returning the 'a' versions of the instructions. Note - // that the difference between a/b is that the former is for double- - // spaced even registers while the latter is for double-spaced odd - // registers. This is for codegen instruction selection purpose. - // For disassembly, it does not matter. - const std::string &name1 = nameWithID(Opcodes[0]); - const std::string &name2 = nameWithID(Opcodes[1]); - if ((name1 == "VMOVDneon" && name2 == "VORRd") || - (name1 == "VMOVQ" && name2 == "VORRq")) { - // Inserting the opening curly brace for this case block. - i.pop(); - o.indent(i) << "{\n"; - i.push(); - - o.indent(i) << "field_t N = fieldFromInstruction(insn, 7, 1), " - << "M = fieldFromInstruction(insn, 5, 1);\n"; - o.indent(i) << "field_t Vn = fieldFromInstruction(insn, 16, 4), " - << "Vm = fieldFromInstruction(insn, 0, 4);\n"; - o.indent(i) << "return (N == M && Vn == Vm) ? " - << Opcodes[0] << " /* " << name1 << " */ : " - << Opcodes[1] << " /* " << name2 << " */ ;\n"; - - // Inserting the closing curly brace for this case block. - i.pop(); - o.indent(i) << "}\n"; - i.push(); - - return true; - } - if (name1 == "LDR" && name2 == "LDRcp") { - o.indent(i) << "return " << Opcodes[0] - << "; // Returning LDR for {LDR, LDRcp}\n"; - return true; - } - if (sameStringExceptEndingChar(name1, name2, 'a', 'b')) { - o.indent(i) << "return " << Opcodes[0] << "; // Returning " << name1 - << " for {" << name1 << ", " << name2 << "}\n"; - return true; - } - - // Otherwise, it does not belong to the known conflict sets. - } - // We don't know how to decode these instructions! Dump the conflict set! - o.indent(i) << "return 0;" << " // Conflict set: "; - for (int i = 0, N = Opcodes.size(); i < N; ++i) { - o << nameWithID(Opcodes[i]); - if (i < (N - 1)) - o << ", "; - else - o << '\n'; - } - return true; - } else { - // Choose the best filter to do the decodings! - Filter &Best = bestFilter(); - if (Best.getNumFiltered() == 1) - emitSingletonDecoder(o, i, Best); - else - bestFilter().emit(o, i); - return false; - } - } -}; - -/////////////// -// Backend // -/////////////// - -class RISCDisassemblerEmitter::RISCDEBackend { -public: - RISCDEBackend(RISCDisassemblerEmitter &frontend) : - NumberedInstructions(), - Opcodes(), - Frontend(frontend), - Target(), - AFC(NULL) - { - populateInstructions(); - - if (Target.getName() == "ARM") { - TargetName = TARGET_ARM; - } else { - errs() << "Target name " << Target.getName() << " not recognized\n"; - assert(0 && "Unknown target"); - } - } - - ~RISCDEBackend() { - if (AFC) { - delete AFC; - AFC = NULL; - } - } - - void getInstructionsByEnumValue(std::vector - &NumberedInstructions) { - // Dig down to the proper namespace. Code shamelessly stolen from - // InstrEnumEmitter.cpp - std::string Namespace; - CodeGenTarget::inst_iterator II, E; - - for (II = Target.inst_begin(), E = Target.inst_end(); II != E; ++II) - if (II->second.Namespace != "TargetInstrInfo") { - Namespace = II->second.Namespace; - break; - } - - assert(!Namespace.empty() && "No instructions defined."); - - Target.getInstructionsByEnumValue(NumberedInstructions); - } - - bool populateInstruction(const CodeGenInstruction &CGI, TARGET_NAME_t TN) { - const Record &Def = *CGI.TheDef; - const std::string &Name = Def.getName(); - uint8_t Form = getByteField(Def, "Form"); - BitsInit &Bits = getBitsField(Def, "Inst"); - - if (TN == TARGET_ARM) { - // FIXME: what about Int_MemBarrierV6 and Int_SyncBarrierV6? - if ((Name != "Int_MemBarrierV7" && Name != "Int_SyncBarrierV7") && - Form == ARM_FORMAT_PSEUDO) - return false; - if (thumbInstruction(Form)) - return false; - if (Name.find("CMPz") != std::string::npos /* || - Name.find("CMNz") != std::string::npos */) - return false; - - // Ignore pseudo instructions. - if (Name == "BXr9" || Name == "BMOVPCRX" || Name == "BMOVPCRXr9") - return false; - - // VLDRQ/VSTRQ can be hanlded with the more generic VLDMD/VSTMD. - if (Name == "VLDRQ" || Name == "VSTRQ") - return false; - - // - // The following special cases are for conflict resolutions. - // - - // RSCSri and RSCSrs set the 's' bit, but are not predicated. We are - // better off using the generic RSCri and RSCrs instructions. - if (Name == "RSCSri" || Name == "RSCSrs") return false; - - // MOVCCr, MOVCCs, MOVCCi, FCYPScc, FCYPDcc, FNEGScc, and FNEGDcc are used - // in the compiler to implement conditional moves. We can ignore them in - // favor of their more generic versions of instructions. - // See also SDNode *ARMDAGToDAGISel::Select(SDValue Op). - if (Name == "MOVCCr" || Name == "MOVCCs" || Name == "MOVCCi" || - Name == "FCPYScc" || Name == "FCPYDcc" || - Name == "FNEGScc" || Name == "FNEGDcc") - return false; - - // Ditto for VMOVDcc, VMOVScc, VNEGDcc, and VNEGScc. - if (Name == "VMOVDcc" || Name == "VMOVScc" || Name == "VNEGDcc" || - Name == "VNEGScc") - return false; - - // Ignore the *_sfp instructions when decoding. They are used by the - // compiler to implement scalar floating point operations using vector - // operations in order to work around some performance issues. - if (Name.find("_sfp") != std::string::npos) return false; - - // LLVM added LDM/STM_UPD which conflicts with LDM/STM. - // Ditto for VLDMS_UPD, VLDMD_UPD, VSTMS_UPD, VSTMD_UPD. - if (Name == "LDM_UPD" || Name == "STM_UPD" || Name == "VLDMS_UPD" || - Name == "VLDMD_UPD" || Name == "VSTMS_UPD" || Name == "VSTMD_UPD") - return false; - - // LDM_RET is a special case of LDM (Load Multiple) where the registers - // loaded include the PC, causing a branch to a loaded address. Ignore - // the LDM_RET instruction when decoding. - if (Name == "LDM_RET") return false; - - // Bcc is in a more generic form than B. Ignore B when decoding. - if (Name == "B") return false; - - // Ignore the non-Darwin BL instructions and the TPsoft (TLS) instruction. - if (Name == "BL" || Name == "BL_pred" || Name == "BLX" || Name == "BX" || - Name == "TPsoft") - return false; - - // Ignore VDUPf[d|q] instructions known to conflict with VDUP32[d-q] for - // decoding. The instruction duplicates an element from an ARM core - // register into every element of the destination vector. There is no - // distinction between data types. - if (Name == "VDUPfd" || Name == "VDUPfq") return false; - - // A8-598: VEXT - // Vector Extract extracts elements from the bottom end of the second - // operand vector and the top end of the first, concatenates them and - // places the result in the destination vector. The elements of the - // vectors are treated as being 8-bit bitfields. There is no distinction - // between data types. The size of the operation can be specified in - // assembler as vext.size. If the value is 16, 32, or 64, the syntax is - // a pseudo-instruction for a VEXT instruction specifying the equivalent - // number of bytes. - // - // Variants VEXTd16, VEXTd32, VEXTd8, and VEXTdf are reduced to VEXTd8; - // variants VEXTq16, VEXTq32, VEXTq8, and VEXTqf are reduced to VEXTq8. - if (Name == "VEXTd16" || Name == "VEXTd32" || Name == "VEXTdf" || - Name == "VEXTq16" || Name == "VEXTq32" || Name == "VEXTqf") - return false; - - // Vector Reverse is similar to Vector Extract. There is no distinction - // between data types, other than size. - // - // VREV64df is equivalent to VREV64d32. - // VREV64qf is equivalent to VREV64q32. - if (Name == "VREV64df" || Name == "VREV64qf") return false; - - // VDUPLNfd is equivalent to VDUPLN32d; VDUPfdf is specialized VDUPLN32d. - // VDUPLNfq is equivalent to VDUPLN32q; VDUPfqf is specialized VDUPLN32q. - // VLD1df is equivalent to VLD1d32. - // VLD1qf is equivalent to VLD1q32. - // VLD2d64 is equivalent to VLD1q64. - // VST1df is equivalent to VST1d32. - // VST1qf is equivalent to VST1q32. - // VST2d64 is equivalent to VST1q64. - if (Name == "VDUPLNfd" || Name == "VDUPfdf" || - Name == "VDUPLNfq" || Name == "VDUPfqf" || - Name == "VLD1df" || Name == "VLD1qf" || Name == "VLD2d64" || - Name == "VST1df" || Name == "VST1qf" || Name == "VST2d64") - return false; - } else if (TN == TARGET_THUMB) { - if (!thumbInstruction(Form)) - return false; - - // Ignore pseudo instructions. - if (Name == "tInt_eh_sjlj_setjmp" || Name == "t2Int_eh_sjlj_setjmp" || - Name == "t2MOVi32imm" || Name == "tBX" || Name == "tBXr9") - return false; - - // LLVM added tLDM_UPD which conflicts with tLDM. - if (Name == "tLDM_UPD") - return false; - - // On Darwin R9 is call-clobbered. Ignore the non-Darwin counterparts. - if (Name == "tBL" || Name == "tBLXi" || Name == "tBLXr") - return false; - - // Ignore the TPsoft (TLS) instructions, which conflict with tBLr9. - if (Name == "tTPsoft" || Name == "t2TPsoft") - return false; - - // Ignore tLEApcrel and tLEApcrelJT, prefer tADDrPCi. - if (Name == "tLEApcrel" || Name == "tLEApcrelJT") - return false; - - // Ignore t2LEApcrel, prefer the generic t2ADD* for disassembly printing. - if (Name == "t2LEApcrel") - return false; - - // Ignore tADDrSP, tADDspr, and tPICADD, prefer the generic tADDhirr. - // Ignore t2SUBrSPs, prefer the t2SUB[S]r[r|s]. - // Ignore t2ADDrSPs, prefer the t2ADD[S]r[r|s]. - if (Name == "tADDrSP" || Name == "tADDspr" || Name == "tPICADD" || - Name == "t2SUBrSPs" || Name == "t2ADDrSPs") - return false; - - // Ignore t2LDRDpci, prefer the generic t2LDRDi8, t2LDRD_PRE, t2LDRD_POST. - if (Name == "t2LDRDpci") - return false; - - // Ignore t2TBB, t2TBH and prefer the generic t2TBBgen, t2TBHgen. - if (Name == "t2TBB" || Name == "t2TBH") - return false; - - // Resolve conflicts: - // - // tBfar conflicts with tBLr9 - // tCMNz conflicts with tCMN (with assembly format strings being equal) - // tPOP_RET/t2LDM_RET conflict with tPOP/t2LDM (ditto) - // tMOVCCi conflicts with tMOVi8 - // tMOVCCr conflicts with tMOVgpr2gpr - // tBR_JTr conflicts with tBRIND - // tSpill conflicts with tSTRspi - // tLDRcp conflicts with tLDRspi - // tRestore conflicts with tLDRspi - // t2LEApcrelJT conflicts with t2LEApcrel - // t2ADDrSPi/t2SUBrSPi have more generic couterparts - if (Name == "tBfar" || - /* Name == "tCMNz" || */ Name == "tCMPzi8" || Name == "tCMPzr" || - Name == "tCMPzhir" || /* Name == "t2CMNzrr" || Name == "t2CMNzrs" || - Name == "t2CMNzri" || */ Name == "t2CMPzrr" || Name == "t2CMPzrs" || - Name == "t2CMPzri" || Name == "tPOP_RET" || Name == "t2LDM_RET" || - Name == "tMOVCCi" || Name == "tMOVCCr" || Name == "tBR_JTr" || - Name == "tSpill" || Name == "tLDRcp" || Name == "tRestore" || - Name == "t2LEApcrelJT" || Name == "t2ADDrSPi" || Name == "t2SUBrSPi") - return false; - } - - // Dumps the instruction encoding format. - switch (TargetName) { - case TARGET_ARM: - case TARGET_THUMB: - DEBUG(errs() << Name << " " << stringForARMFormat((ARMFormat)Form)); - break; - } - - DEBUG({ - errs() << " "; - - // Dumps the instruction encoding bits. - dumpBits(errs(), Bits); - - errs() << '\n'; - - // Dumps the list of operand info. - for (unsigned i = 0, e = CGI.OperandList.size(); i != e; ++i) { - CodeGenInstruction::OperandInfo Info = CGI.OperandList[i]; - const std::string &OperandName = Info.Name; - const Record &OperandDef = *Info.Rec; - - errs() << "\t" << OperandName << " (" << OperandDef.getName() << ")\n"; - } - }); - - return true; - } - - void populateInstructions() { - getInstructionsByEnumValue(NumberedInstructions); - - uint16_t numUIDs = NumberedInstructions.size(); - uint16_t uid; - - const char *instClass = NULL; - - switch (TargetName) { - case TARGET_ARM: - instClass = "InstARM"; - break; - default: - assert(0 && "Unreachable code!"); - } - - for (uid = 0; uid < numUIDs; uid++) { - // filter out intrinsics - if (!NumberedInstructions[uid]->TheDef->isSubClassOf(instClass)) - continue; - - if (populateInstruction(*NumberedInstructions[uid], TargetName)) - Opcodes.push_back(uid); - } - - // Special handling for the ARM chip, which supports two modes of execution. - // This branch handles the Thumb opcodes. - if (TargetName == TARGET_ARM) { - for (uid = 0; uid < numUIDs; uid++) { - // filter out intrinsics - if (!NumberedInstructions[uid]->TheDef->isSubClassOf("InstARM") - && !NumberedInstructions[uid]->TheDef->isSubClassOf("InstThumb")) - continue; - - if (populateInstruction(*NumberedInstructions[uid], TARGET_THUMB)) - Opcodes2.push_back(uid); - } - } - } - - // Emits disassembler code for instruction decoding. This delegates to the - // FilterChooser instance to do the heavy lifting. - void emit(raw_ostream &o) { - Indenter i; - std::string s; - raw_string_ostream ro(s); - - switch (TargetName) { - case TARGET_ARM: - Frontend.EmitSourceFileHeader("ARM Disassembler", ro); - break; - default: - assert(0 && "Unreachable code!"); - } - - ro.flush(); - o << s; - - o.indent(i) << "#include \n"; - o.indent(i) << "#include \n"; - o << '\n'; - o << "namespace llvm {\n\n"; - - AbstractFilterChooser::setTargetName(TargetName); - - switch (TargetName) { - case TARGET_ARM: { - // Emit common utility and ARM ISA decoder. - AFC = new FilterChooser<32>(NumberedInstructions, Opcodes); - AFC->emitTop(o, i); - delete AFC; - - // Emit Thumb ISA decoder as well. - AbstractFilterChooser::setTargetName(TARGET_THUMB); - AFC = new FilterChooser<32>(NumberedInstructions, Opcodes2); - AFC->emitBot(o, i); - break; - } - default: - assert(0 && "Unreachable code!"); - } - - o << "\n} // End llvm namespace \n"; - } - -protected: - std::vector NumberedInstructions; - std::vector Opcodes; - // Special case for the ARM chip, which supports ARM and Thumb ISAs. - // Opcodes2 will be populated with the Thumb opcodes. - std::vector Opcodes2; - RISCDisassemblerEmitter &Frontend; - CodeGenTarget Target; - AbstractFilterChooser *AFC; - - TARGET_NAME_t TargetName; -}; - -///////////////////////// -// Backend interface // -///////////////////////// - -void RISCDisassemblerEmitter::initBackend() -{ - Backend = new RISCDEBackend(*this); -} - -void RISCDisassemblerEmitter::run(raw_ostream &o) -{ - Backend->emit(o); -} - -void RISCDisassemblerEmitter::shutdownBackend() -{ - delete Backend; - Backend = NULL; -} Removed: llvm/trunk/utils/TableGen/RISCDisassemblerEmitter.h URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/utils/TableGen/RISCDisassemblerEmitter.h?rev=98639&view=auto ============================================================================== --- llvm/trunk/utils/TableGen/RISCDisassemblerEmitter.h (original) +++ llvm/trunk/utils/TableGen/RISCDisassemblerEmitter.h (removed) @@ -1,48 +0,0 @@ -//===- RISCDisassemblerEmitter.h - Disassembler Generator -------*- C++ -*-===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// -// FIXME: document -// -//===----------------------------------------------------------------------===// - -#ifndef RISCDISASSEMBLEREMITTER_H -#define RISCDISASSEMBLEREMITTER_H - -#include "TableGenBackend.h" - -#include - -namespace llvm { - -class RISCDisassemblerEmitter : public TableGenBackend { - RecordKeeper &Records; -public: - RISCDisassemblerEmitter(RecordKeeper &R) : Records(R) { - initBackend(); - } - - ~RISCDisassemblerEmitter() { - shutdownBackend(); - } - - // run - Output the code emitter - void run(raw_ostream &o); - -private: - class RISCDEBackend; - - RISCDEBackend *Backend; - - void initBackend(); - void shutdownBackend(); -}; - -} // end llvm namespace - -#endif Modified: llvm/trunk/utils/TableGen/TableGen.cpp URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/utils/TableGen/TableGen.cpp?rev=98640&r1=98639&r2=98640&view=diff ============================================================================== --- llvm/trunk/utils/TableGen/TableGen.cpp (original) +++ llvm/trunk/utils/TableGen/TableGen.cpp Tue Mar 16 11:59:47 2010 @@ -31,7 +31,6 @@ #include "OptParserEmitter.h" #include "Record.h" #include "RegisterInfoEmitter.h" -#include "RISCDisassemblerEmitter.h" #include "SubtargetEmitter.h" #include "TGParser.h" #include "llvm/Support/CommandLine.h" @@ -49,7 +48,6 @@ GenEmitter, GenRegisterEnums, GenRegister, GenRegisterHeader, GenInstrEnums, GenInstrs, GenAsmWriter, GenAsmMatcher, - GenRISCDisassembler, GenDisassembler, GenCallingConv, GenClangDiagsDefs, @@ -86,9 +84,6 @@ "Generate calling convention descriptions"), clEnumValN(GenAsmWriter, "gen-asm-writer", "Generate assembly writer"), - clEnumValN(GenRISCDisassembler, "gen-risc-disassembler", - "Generate disassembler for fixed instruction" - " length"), clEnumValN(GenDisassembler, "gen-disassembler", "Generate disassembler"), clEnumValN(GenAsmMatcher, "gen-asm-matcher", @@ -234,9 +229,6 @@ case GenAsmWriter: AsmWriterEmitter(Records).run(*Out); break; - case GenRISCDisassembler: - RISCDisassemblerEmitter(Records).run(*Out); - break; case GenAsmMatcher: AsmMatcherEmitter(Records).run(*Out); break; From bob.wilson at apple.com Tue Mar 16 12:01:13 2010 From: bob.wilson at apple.com (Bob Wilson) Date: Tue, 16 Mar 2010 10:01:13 -0700 Subject: [llvm-commits] [llvm] r98637 - in /llvm/trunk: ./ lib/Target/ARM/ lib/Target/ARM/AsmPrinter/ lib/Target/ARM/Disassembler/ test/CodeGen/ARM/ test/CodeGen/Thumb2/ utils/TableGen/ In-Reply-To: <20100316163655.029872A6C12C@llvm.org> References: <20100316163655.029872A6C12C@llvm.org> Message-ID: <38B92BD5-443C-47B4-B71D-5AABF1FB1462@apple.com> I've reverted this since it broke the buildbots. I'd like a chance to review this before you re-commit with fixes. On Mar 16, 2010, at 9:36 AM, Johnny Chen wrote: > Author: johnny > Date: Tue Mar 16 11:36:54 2010 > New Revision: 98637 > > URL: http://llvm.org/viewvc/llvm-project?rev=98637&view=rev > Log: > Initial ARM/Thumb disassembler check-in. It consists of a tablgen backend > (RISCDisassemblerEmitter) which emits the decoder functions for ARM and Thumb, > and the disassembler core which invokes the decoder function and builds up the > MCInst based on the decoded Opcode. > > Added sub-formats to the NeonI/NeonXI instructions to further refine the NEONFrm > instructions to help disassembly. > > We also changed the output of the addressing modes to omit the '+' from the > assembler syntax #+/- or +/-. See, for example, A8.6.57/58/60. > > And modified test cases to not expect '+' in +reg or #+num. For example, > > ; CHECK: ldr.w r9, [r7, #28] > > Added: > llvm/trunk/lib/Target/ARM/Disassembler/ > llvm/trunk/lib/Target/ARM/Disassembler/ARMDisassembler.cpp > llvm/trunk/lib/Target/ARM/Disassembler/ARMDisassembler.h > llvm/trunk/lib/Target/ARM/Disassembler/ARMDisassemblerCore.cpp > llvm/trunk/lib/Target/ARM/Disassembler/ARMDisassemblerCore.h > llvm/trunk/lib/Target/ARM/Disassembler/Makefile > llvm/trunk/lib/Target/ARM/Disassembler/ThumbDisassemblerCore.cpp.inc > llvm/trunk/utils/TableGen/RISCDisassemblerEmitter.cpp > llvm/trunk/utils/TableGen/RISCDisassemblerEmitter.h > Modified: > llvm/trunk/Makefile.rules > llvm/trunk/lib/Target/ARM/ARMAddressingModes.h > llvm/trunk/lib/Target/ARM/ARMInstrFormats.td > llvm/trunk/lib/Target/ARM/ARMInstrNEON.td > llvm/trunk/lib/Target/ARM/AsmPrinter/ARMAsmPrinter.cpp > llvm/trunk/lib/Target/ARM/AsmPrinter/ARMInstPrinter.cpp > llvm/trunk/lib/Target/ARM/AsmPrinter/ARMInstPrinter.h > llvm/trunk/lib/Target/ARM/Makefile > llvm/trunk/lib/Target/ARM/Thumb2ITBlockPass.cpp > llvm/trunk/test/CodeGen/ARM/2009-10-27-double-align.ll > llvm/trunk/test/CodeGen/ARM/2009-10-30.ll > llvm/trunk/test/CodeGen/ARM/arm-negative-stride.ll > llvm/trunk/test/CodeGen/ARM/globals.ll > llvm/trunk/test/CodeGen/ARM/ldrd.ll > llvm/trunk/test/CodeGen/ARM/str_pre-2.ll > llvm/trunk/test/CodeGen/ARM/tls2.ll > llvm/trunk/test/CodeGen/Thumb2/ldr-str-imm12.ll > llvm/trunk/test/CodeGen/Thumb2/thumb2-ldr.ll > llvm/trunk/test/CodeGen/Thumb2/thumb2-ldrh.ll > llvm/trunk/test/CodeGen/Thumb2/thumb2-str.ll > llvm/trunk/test/CodeGen/Thumb2/thumb2-str_pre.ll > llvm/trunk/test/CodeGen/Thumb2/thumb2-strb.ll > llvm/trunk/test/CodeGen/Thumb2/thumb2-strh.ll > llvm/trunk/utils/TableGen/DisassemblerEmitter.cpp > llvm/trunk/utils/TableGen/TableGen.cpp > > Modified: llvm/trunk/Makefile.rules > URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/Makefile.rules?rev=98637&r1=98636&r2=98637&view=diff > ============================================================================== > --- llvm/trunk/Makefile.rules (original) > +++ llvm/trunk/Makefile.rules Tue Mar 16 11:36:54 2010 > @@ -1614,6 +1614,11 @@ > $(Echo) "Building $( $(Verb) $(TableGen) -gen-tgt-intrinsic -o $(call SYSPATH, $@) $< > > +$(ObjDir)/ARMDisassemblerTables.inc.tmp : ARM.td $(ObjDir)/.dir > + $(Echo) "Building ARM disassembly tables with tblgen" > + $(Verb) $(TableGen) -gen-risc-disassembler -o $(call SYSPATH, $@) $< > + > + > clean-local:: > -$(Verb) $(RM) -f $(INCFiles) > > > Modified: llvm/trunk/lib/Target/ARM/ARMAddressingModes.h > URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Target/ARM/ARMAddressingModes.h?rev=98637&r1=98636&r2=98637&view=diff > ============================================================================== > --- llvm/trunk/lib/Target/ARM/ARMAddressingModes.h (original) > +++ llvm/trunk/lib/Target/ARM/ARMAddressingModes.h Tue Mar 16 11:36:54 2010 > @@ -35,6 +35,10 @@ > add = '+', sub = '-' > }; > > + static inline const char *getAddrOpcStr(AddrOpc Op) { > + return Op == sub ? "-" : ""; > + } > + > static inline const char *getShiftOpcStr(ShiftOpc Op) { > switch (Op) { > default: assert(0 && "Unknown shift opc!"); > @@ -127,6 +131,20 @@ > return (Imm >> 8) * 2; > } > > + /// getSOImmValOneRotate - Try to handle Imm with an immediate shifter > + /// operand, computing the rotate amount to use. If this immediate value > + /// cannot be handled with a single shifter-op, return 0. > + static inline unsigned getSOImmValOneRotate(unsigned Imm) { > + // A5.2.4 Constants with multiple encodings > + // The lowest unsigned value of rotation wins! > + for (unsigned R = 1; R <= 15; ++R) > + if ((Imm & rotr32(~255U, 2*R)) == 0) > + return 2*R; > + > + // Failed to find a suitable rotate amount. > + return 0; > + } > + > /// getSOImmValRotate - Try to handle Imm with an immediate shifter operand, > /// computing the rotate amount to use. If this immediate value cannot be > /// handled with a single shifter-op, determine a good rotate amount that will > @@ -179,7 +197,7 @@ > // of zero. > if ((Arg & ~255U) == 0) return Arg; > > - unsigned RotAmt = getSOImmValRotate(Arg); > + unsigned RotAmt = getSOImmValOneRotate(Arg); > > // If this cannot be handled with a single shifter_op, bail out. > if (rotr32(~255U, RotAmt) & Arg) > > Modified: llvm/trunk/lib/Target/ARM/ARMInstrFormats.td > URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Target/ARM/ARMInstrFormats.td?rev=98637&r1=98636&r2=98637&view=diff > ============================================================================== > --- llvm/trunk/lib/Target/ARM/ARMInstrFormats.td (original) > +++ llvm/trunk/lib/Target/ARM/ARMInstrFormats.td Tue Mar 16 11:36:54 2010 > @@ -1464,6 +1464,29 @@ > // ARM NEON Instruction templates. > // > > +// NSFormat specifies further details of a NEON instruction. This is used by > +// the disassembler to classify NEONFrm instructions for disassembly purpose. > +class NSFormat val> { > + bits<5> Value = val; > +} > +def NSFormatNone : NSFormat<0>; > +def VLDSTLaneFrm : NSFormat<1>; > +def VLDSTLaneDblFrm : NSFormat<2>; > +def VLDSTRQFrm : NSFormat<3>; > +def NVdImmFrm : NSFormat<4>; > +def NVdVmImmFrm : NSFormat<5>; > +def NVdVmImmVCVTFrm : NSFormat<6>; > +def NVdVmImmVDupLaneFrm : NSFormat<7>; > +def NVdVmImmVSHLLFrm : NSFormat<8>; > +def NVectorShuffleFrm : NSFormat<9>; > +def NVectorShiftFrm : NSFormat<10>; > +def NVectorShift2Frm : NSFormat<11>; > +def NVdVnVmImmFrm : NSFormat<12>; > +def NVdVnVmImmVectorShiftFrm : NSFormat<13>; > +def NVdVnVmImmVectorExtractFrm : NSFormat<14>; > +def NVdVnVmImmMulScalarFrm : NSFormat<15>; > +def VTBLFrm : NSFormat<16>; > + > class NeonI string opc, string dt, string asm, string cstr, list pattern> > : InstARM { > @@ -1474,6 +1497,8 @@ > !strconcat("\t", asm)); > let Pattern = pattern; > list Predicates = [HasNEON]; > + NSFormat NSF = NSFormatNone; // For disassembly. > + bits<5> NSForm = NSFormatNone.Value; // For disassembly. > } > > // Same as NeonI except it does not have a "data type" specifier. > @@ -1485,6 +1510,8 @@ > let AsmString = !strconcat(!strconcat(opc, "${p}"), !strconcat("\t", asm)); > let Pattern = pattern; > list Predicates = [HasNEON]; > + NSFormat NSF = NSFormatNone; // For disassembly. > + bits<5> NSForm = NSFormatNone.Value; // For disassembly. > } > > class NI @@ -1497,6 +1524,8 @@ > string asm, list pattern> > : NeonXI pattern> { > + let NSF = VLDSTRQFrm; // For disassembly. > + let NSForm = VLDSTRQFrm.Value; // For disassembly. > } > > class NLdSt op21_20, bits<4> op11_8, bits<4> op7_4, > @@ -1509,6 +1538,8 @@ > let Inst{21-20} = op21_20; > let Inst{11-8} = op11_8; > let Inst{7-4} = op7_4; > + let NSF = VLDSTLaneFrm; // For disassembly. > + let NSForm = VLDSTLaneFrm.Value; // For disassembly. > } > > class NDataI @@ -1538,6 +1569,8 @@ > let Inst{6} = op6; > let Inst{5} = op5; > let Inst{4} = op4; > + let NSF = NVdImmFrm; // For disassembly. > + let NSForm = NVdImmFrm.Value; // For disassembly. > } > > // NEON 2 vector register format. > @@ -1553,6 +1586,8 @@ > let Inst{11-7} = op11_7; > let Inst{6} = op6; > let Inst{4} = op4; > + let NSF = NVdVmImmFrm; // For disassembly. > + let NSForm = NVdVmImmFrm.Value; // For disassembly. > } > > // Same as N2V except it doesn't have a datatype suffix. > @@ -1568,6 +1603,8 @@ > let Inst{11-7} = op11_7; > let Inst{6} = op6; > let Inst{4} = op4; > + let NSF = NVdVmImmFrm; // For disassembly. > + let NSForm = NVdVmImmFrm.Value; // For disassembly. > } > > // NEON 2 vector register with immediate. > @@ -1581,6 +1618,8 @@ > let Inst{7} = op7; > let Inst{6} = op6; > let Inst{4} = op4; > + let NSF = NVdVmImmFrm; // For disassembly. > + let NSForm = NVdVmImmFrm.Value; // For disassembly. > } > > // NEON 3 vector register format. > @@ -1594,6 +1633,8 @@ > let Inst{11-8} = op11_8; > let Inst{6} = op6; > let Inst{4} = op4; > + let NSF = NVdVnVmImmFrm; // For disassembly. > + let NSForm = NVdVnVmImmFrm.Value; // For disassembly. > } > > // Same as N3VX except it doesn't have a data type suffix. > @@ -1607,6 +1648,8 @@ > let Inst{11-8} = op11_8; > let Inst{6} = op6; > let Inst{4} = op4; > + let NSF = NVdVnVmImmFrm; // For disassembly. > + let NSForm = NVdVnVmImmFrm.Value; // For disassembly. > } > > // NEON VMOVs between scalar and core registers. > > Modified: llvm/trunk/lib/Target/ARM/ARMInstrNEON.td > URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Target/ARM/ARMInstrNEON.td?rev=98637&r1=98636&r2=98637&view=diff > ============================================================================== > --- llvm/trunk/lib/Target/ARM/ARMInstrNEON.td (original) > +++ llvm/trunk/lib/Target/ARM/ARMInstrNEON.td Tue Mar 16 11:36:54 2010 > @@ -213,7 +213,10 @@ > class VLD2Ddbl op7_4, string OpcodeStr, string Dt> > : NLdSt<0,0b10,0b1001,op7_4, (outs DPR:$dst1, DPR:$dst2), > (ins addrmode6:$addr), IIC_VLD2, > - OpcodeStr, Dt, "\\{$dst1, $dst2\\}, $addr", "", []>; > + OpcodeStr, Dt, "\\{$dst1, $dst2\\}, $addr", "", []> { > + let NSF = VLDSTLaneDblFrm; // For disassembly. > + let NSForm = VLDSTLaneDblFrm.Value; // For disassembly. > +} > > def VLD2d8D : VLD2Ddbl<0b0000, "vld2", "8">; > def VLD2d16D : VLD2Ddbl<0b0100, "vld2", "16">; > @@ -228,7 +231,10 @@ > : NLdSt<0,0b10,0b0101,op7_4, (outs DPR:$dst1, DPR:$dst2, DPR:$dst3, GPR:$wb), > (ins addrmode6:$addr), IIC_VLD3, > OpcodeStr, Dt, "\\{$dst1, $dst2, $dst3\\}, $addr", > - "$addr.addr = $wb", []>; > + "$addr.addr = $wb", []> { > + let NSF = VLDSTLaneDblFrm; // For disassembly. > + let NSForm = VLDSTLaneDblFrm.Value; // For disassembly. > +} > > def VLD3d8 : VLD3D<0b0000, "vld3", "8">; > def VLD3d16 : VLD3D<0b0100, "vld3", "16">; > @@ -260,7 +266,10 @@ > (outs DPR:$dst1, DPR:$dst2, DPR:$dst3, DPR:$dst4, GPR:$wb), > (ins addrmode6:$addr), IIC_VLD4, > OpcodeStr, Dt, "\\{$dst1, $dst2, $dst3, $dst4\\}, $addr", > - "$addr.addr = $wb", []>; > + "$addr.addr = $wb", []> { > + let NSF = VLDSTLaneDblFrm; // For disassembly. > + let NSForm = VLDSTLaneDblFrm.Value; // For disassembly. > +} > > def VLD4d8 : VLD4D<0b0000, "vld4", "8">; > def VLD4d16 : VLD4D<0b0100, "vld4", "16">; > @@ -297,12 +306,28 @@ > def VLD2LNd32 : VLD2LN<0b1001, "vld2", "32"> { let Inst{6} = 0; } > > // vld2 to double-spaced even registers. > -def VLD2LNq16a: VLD2LN<0b0101, "vld2", "16"> { let Inst{5} = 1; } > -def VLD2LNq32a: VLD2LN<0b1001, "vld2", "32"> { let Inst{6} = 1; } > +def VLD2LNq16a: VLD2LN<0b0101, "vld2", "16"> { > + let Inst{5} = 1; > + let NSF = VLDSTLaneDblFrm; // For disassembly. > + let NSForm = VLDSTLaneDblFrm.Value; // For disassembly. > +} > +def VLD2LNq32a: VLD2LN<0b1001, "vld2", "32"> { > + let Inst{6} = 1; > + let NSF = VLDSTLaneDblFrm; // For disassembly. > + let NSForm = VLDSTLaneDblFrm.Value; // For disassembly. > +} > > // vld2 to double-spaced odd registers. > -def VLD2LNq16b: VLD2LN<0b0101, "vld2", "16"> { let Inst{5} = 1; } > -def VLD2LNq32b: VLD2LN<0b1001, "vld2", "32"> { let Inst{6} = 1; } > +def VLD2LNq16b: VLD2LN<0b0101, "vld2", "16"> { > + let Inst{5} = 1; > + let NSF = VLDSTLaneDblFrm; // For disassembly. > + let NSForm = VLDSTLaneDblFrm.Value; // For disassembly. > +} > +def VLD2LNq32b: VLD2LN<0b1001, "vld2", "32"> { > + let Inst{6} = 1; > + let NSF = VLDSTLaneDblFrm; // For disassembly. > + let NSForm = VLDSTLaneDblFrm.Value; // For disassembly. > +} > > // VLD3LN : Vector Load (single 3-element structure to one lane) > class VLD3LN op11_8, string OpcodeStr, string Dt> > @@ -318,7 +343,11 @@ > def VLD3LNd32 : VLD3LN<0b1010, "vld3", "32"> { let Inst{6-4} = 0b000; } > > // vld3 to double-spaced even registers. > -def VLD3LNq16a: VLD3LN<0b0110, "vld3", "16"> { let Inst{5-4} = 0b10; } > +def VLD3LNq16a: VLD3LN<0b0110, "vld3", "16"> { > + let Inst{5-4} = 0b10; > + let NSF = VLDSTLaneDblFrm; // For disassembly. > + let NSForm = VLDSTLaneDblFrm.Value; // For disassembly. > +} > def VLD3LNq32a: VLD3LN<0b1010, "vld3", "32"> { let Inst{6-4} = 0b100; } > > // vld3 to double-spaced odd registers. > @@ -340,12 +369,28 @@ > def VLD4LNd32 : VLD4LN<0b1011, "vld4", "32"> { let Inst{6} = 0; } > > // vld4 to double-spaced even registers. > -def VLD4LNq16a: VLD4LN<0b0111, "vld4", "16"> { let Inst{5} = 1; } > -def VLD4LNq32a: VLD4LN<0b1011, "vld4", "32"> { let Inst{6} = 1; } > +def VLD4LNq16a: VLD4LN<0b0111, "vld4", "16"> { > + let Inst{5} = 1; > + let NSF = VLDSTLaneDblFrm; // For disassembly. > + let NSForm = VLDSTLaneDblFrm.Value; // For disassembly. > +} > +def VLD4LNq32a: VLD4LN<0b1011, "vld4", "32"> { > + let Inst{6} = 1; > + let NSF = VLDSTLaneDblFrm; // For disassembly. > + let NSForm = VLDSTLaneDblFrm.Value; // For disassembly. > +} > > // vld4 to double-spaced odd registers. > -def VLD4LNq16b: VLD4LN<0b0111, "vld4", "16"> { let Inst{5} = 1; } > -def VLD4LNq32b: VLD4LN<0b1011, "vld4", "32"> { let Inst{6} = 1; } > +def VLD4LNq16b: VLD4LN<0b0111, "vld4", "16"> { > + let Inst{5} = 1; > + let NSF = VLDSTLaneDblFrm; // For disassembly. > + let NSForm = VLDSTLaneDblFrm.Value; // For disassembly. > +} > +def VLD4LNq32b: VLD4LN<0b1011, "vld4", "32"> { > + let Inst{6} = 1; > + let NSF = VLDSTLaneDblFrm; // For disassembly. > + let NSForm = VLDSTLaneDblFrm.Value; // For disassembly. > +} > > // VLD1DUP : Vector Load (single element to all lanes) > // VLD2DUP : Vector Load (single 2-element structure to all lanes) > @@ -433,7 +478,10 @@ > class VST2Ddbl op7_4, string OpcodeStr, string Dt> > : NLdSt<0, 0b00, 0b1001, op7_4, (outs), > (ins addrmode6:$addr, DPR:$src1, DPR:$src2), IIC_VST, > - OpcodeStr, Dt, "\\{$src1, $src2\\}, $addr", "", []>; > + OpcodeStr, Dt, "\\{$src1, $src2\\}, $addr", "", []> { > + let NSF = VLDSTLaneDblFrm; // For disassembly. > + let NSForm = VLDSTLaneDblFrm.Value; // For disassembly. > +} > > def VST2d8D : VST2Ddbl<0b0000, "vst2", "8">; > def VST2d16D : VST2Ddbl<0b0100, "vst2", "16">; > @@ -448,7 +496,10 @@ > : NLdSt<0,0b00,0b0101,op7_4, (outs GPR:$wb), > (ins addrmode6:$addr, DPR:$src1, DPR:$src2, DPR:$src3), IIC_VST, > OpcodeStr, Dt, "\\{$src1, $src2, $src3\\}, $addr", > - "$addr.addr = $wb", []>; > + "$addr.addr = $wb", []> { > + let NSF = VLDSTLaneDblFrm; // For disassembly. > + let NSForm = VLDSTLaneDblFrm.Value; // For disassembly. > +} > > def VST3d8 : VST3D<0b0000, "vst3", "8">; > def VST3d16 : VST3D<0b0100, "vst3", "16">; > @@ -478,7 +529,10 @@ > : NLdSt<0,0b00,0b0001,op7_4, (outs GPR:$wb), > (ins addrmode6:$addr, DPR:$src1, DPR:$src2, DPR:$src3, DPR:$src4), > IIC_VST, OpcodeStr, Dt, "\\{$src1, $src2, $src3, $src4\\}, $addr", > - "$addr.addr = $wb", []>; > + "$addr.addr = $wb", []> { > + let NSF = VLDSTLaneDblFrm; // For disassembly. > + let NSForm = VLDSTLaneDblFrm.Value; // For disassembly. > +} > > def VST4d8 : VST4D<0b0000, "vst4", "8">; > def VST4d16 : VST4D<0b0100, "vst4", "16">; > @@ -515,12 +569,28 @@ > def VST2LNd32 : VST2LN<0b1001, "vst2", "32"> { let Inst{6} = 0; } > > // vst2 to double-spaced even registers. > -def VST2LNq16a: VST2LN<0b0101, "vst2", "16"> { let Inst{5} = 1; } > -def VST2LNq32a: VST2LN<0b1001, "vst2", "32"> { let Inst{6} = 1; } > +def VST2LNq16a: VST2LN<0b0101, "vst2", "16"> { > + let Inst{5} = 1; > + let NSF = VLDSTLaneDblFrm; // For disassembly. > + let NSForm = VLDSTLaneDblFrm.Value; // For disassembly. > +} > +def VST2LNq32a: VST2LN<0b1001, "vst2", "32"> { > + let Inst{6} = 1; > + let NSF = VLDSTLaneDblFrm; // For disassembly. > + let NSForm = VLDSTLaneDblFrm.Value; // For disassembly. > +} > > // vst2 to double-spaced odd registers. > -def VST2LNq16b: VST2LN<0b0101, "vst2", "16"> { let Inst{5} = 1; } > -def VST2LNq32b: VST2LN<0b1001, "vst2", "32"> { let Inst{6} = 1; } > +def VST2LNq16b: VST2LN<0b0101, "vst2", "16"> { > + let Inst{5} = 1; > + let NSF = VLDSTLaneDblFrm; // For disassembly. > + let NSForm = VLDSTLaneDblFrm.Value; // For disassembly. > +} > +def VST2LNq32b: VST2LN<0b1001, "vst2", "32"> { > + let Inst{6} = 1; > + let NSF = VLDSTLaneDblFrm; // For disassembly. > + let NSForm = VLDSTLaneDblFrm.Value; // For disassembly. > +} > > // VST3LN : Vector Store (single 3-element structure from one lane) > class VST3LN op11_8, string OpcodeStr, string Dt> > @@ -535,12 +605,28 @@ > def VST3LNd32 : VST3LN<0b1010, "vst3", "32"> { let Inst{6-4} = 0b000; } > > // vst3 to double-spaced even registers. > -def VST3LNq16a: VST3LN<0b0110, "vst3", "16"> { let Inst{5-4} = 0b10; } > -def VST3LNq32a: VST3LN<0b1010, "vst3", "32"> { let Inst{6-4} = 0b100; } > +def VST3LNq16a: VST3LN<0b0110, "vst3", "16"> { > + let Inst{5-4} = 0b10; > + let NSF = VLDSTLaneDblFrm; // For disassembly. > + let NSForm = VLDSTLaneDblFrm.Value; // For disassembly. > +} > +def VST3LNq32a: VST3LN<0b1010, "vst3", "32"> { > + let Inst{6-4} = 0b100; > + let NSF = VLDSTLaneDblFrm; // For disassembly. > + let NSForm = VLDSTLaneDblFrm.Value; // For disassembly. > +} > > // vst3 to double-spaced odd registers. > -def VST3LNq16b: VST3LN<0b0110, "vst3", "16"> { let Inst{5-4} = 0b10; } > -def VST3LNq32b: VST3LN<0b1010, "vst3", "32"> { let Inst{6-4} = 0b100; } > +def VST3LNq16b: VST3LN<0b0110, "vst3", "16"> { > + let Inst{5-4} = 0b10; > + let NSF = VLDSTLaneDblFrm; // For disassembly. > + let NSForm = VLDSTLaneDblFrm.Value; // For disassembly. > +} > +def VST3LNq32b: VST3LN<0b1010, "vst3", "32"> { > + let Inst{6-4} = 0b100; > + let NSF = VLDSTLaneDblFrm; // For disassembly. > + let NSForm = VLDSTLaneDblFrm.Value; // For disassembly. > +} > > // VST4LN : Vector Store (single 4-element structure from one lane) > class VST4LN op11_8, string OpcodeStr, string Dt> > @@ -556,12 +642,28 @@ > def VST4LNd32 : VST4LN<0b1011, "vst4", "32"> { let Inst{6} = 0; } > > // vst4 to double-spaced even registers. > -def VST4LNq16a: VST4LN<0b0111, "vst4", "16"> { let Inst{5} = 1; } > -def VST4LNq32a: VST4LN<0b1011, "vst4", "32"> { let Inst{6} = 1; } > +def VST4LNq16a: VST4LN<0b0111, "vst4", "16"> { > + let Inst{5} = 1; > + let NSF = VLDSTLaneDblFrm; // For disassembly. > + let NSForm = VLDSTLaneDblFrm.Value; // For disassembly. > +} > +def VST4LNq32a: VST4LN<0b1011, "vst4", "32"> { > + let Inst{6} = 1; > + let NSF = VLDSTLaneDblFrm; // For disassembly. > + let NSForm = VLDSTLaneDblFrm.Value; // For disassembly. > +} > > // vst4 to double-spaced odd registers. > -def VST4LNq16b: VST4LN<0b0111, "vst4", "16"> { let Inst{5} = 1; } > -def VST4LNq32b: VST4LN<0b1011, "vst4", "32"> { let Inst{6} = 1; } > +def VST4LNq16b: VST4LN<0b0111, "vst4", "16"> { > + let Inst{5} = 1; > + let NSF = VLDSTLaneDblFrm; // For disassembly. > + let NSForm = VLDSTLaneDblFrm.Value; // For disassembly. > +} > +def VST4LNq32b: VST4LN<0b1011, "vst4", "32"> { > + let Inst{6} = 1; > + let NSF = VLDSTLaneDblFrm; // For disassembly. > + let NSForm = VLDSTLaneDblFrm.Value; // For disassembly. > +} > > } // mayStore = 1, hasExtraSrcRegAllocReq = 1 > > @@ -668,12 +770,18 @@ > : N2V<0b11, 0b11, op19_18, 0b10, op11_7, 0, 0, (outs DPR:$dst1, DPR:$dst2), > (ins DPR:$src1, DPR:$src2), IIC_VPERMD, > OpcodeStr, Dt, "$dst1, $dst2", > - "$src1 = $dst1, $src2 = $dst2", []>; > + "$src1 = $dst1, $src2 = $dst2", []> { > + let NSF = NVectorShuffleFrm; // For disassembly. > + let NSForm = NVectorShuffleFrm.Value; // For disassembly. > +} > class N2VQShuffle op19_18, bits<5> op11_7, > InstrItinClass itin, string OpcodeStr, string Dt> > : N2V<0b11, 0b11, op19_18, 0b10, op11_7, 1, 0, (outs QPR:$dst1, QPR:$dst2), > (ins QPR:$src1, QPR:$src2), itin, OpcodeStr, Dt, "$dst1, $dst2", > - "$src1 = $dst1, $src2 = $dst2", []>; > + "$src1 = $dst1, $src2 = $dst2", []> { > + let NSF = NVectorShuffleFrm; // For disassembly. > + let NSForm = NVectorShuffleFrm.Value; // For disassembly. > +} > > // Basic 3-register operations: single-, double- and quad-register. > class N3VS op21_20, bits<4> op11_8, bit op4, > @@ -715,6 +823,8 @@ > (Ty (ShOp (Ty DPR:$src1), > (Ty (NEONvduplane (Ty DPR_VFP2:$src2), imm:$lane)))))]>{ > let isCommutable = 0; > + let NSF = NVdVnVmImmMulScalarFrm; // For disassembly. > + let NSForm = NVdVnVmImmMulScalarFrm.Value; // For disassembly. > } > class N3VDSL16 op21_20, bits<4> op11_8, > string OpcodeStr, string Dt, ValueType Ty, SDNode ShOp> > @@ -725,6 +835,8 @@ > (Ty (ShOp (Ty DPR:$src1), > (Ty (NEONvduplane (Ty DPR_8:$src2), imm:$lane)))))]> { > let isCommutable = 0; > + let NSF = NVdVnVmImmMulScalarFrm; // For disassembly. > + let NSForm = NVdVnVmImmMulScalarFrm.Value; // For disassembly. > } > > class N3VQ op21_20, bits<4> op11_8, bit op4, > @@ -756,6 +868,8 @@ > (ResTy (NEONvduplane (OpTy DPR_VFP2:$src2), > imm:$lane)))))]> { > let isCommutable = 0; > + let NSF = NVdVnVmImmMulScalarFrm; // For disassembly. > + let NSForm = NVdVnVmImmMulScalarFrm.Value; // For disassembly. > } > class N3VQSL16 op21_20, bits<4> op11_8, string OpcodeStr, string Dt, > ValueType ResTy, ValueType OpTy, SDNode ShOp> > @@ -767,6 +881,8 @@ > (ResTy (NEONvduplane (OpTy DPR_8:$src2), > imm:$lane)))))]> { > let isCommutable = 0; > + let NSF = NVdVnVmImmMulScalarFrm; // For disassembly. > + let NSForm = NVdVnVmImmMulScalarFrm.Value; // For disassembly. > } > > // Basic 3-register intrinsics, both double- and quad-register. > @@ -789,6 +905,8 @@ > (Ty (NEONvduplane (Ty DPR_VFP2:$src2), > imm:$lane)))))]> { > let isCommutable = 0; > + let NSF = NVdVnVmImmMulScalarFrm; // For disassembly. > + let NSForm = NVdVnVmImmMulScalarFrm.Value; // For disassembly. > } > class N3VDIntSL16 op21_20, bits<4> op11_8, InstrItinClass itin, > string OpcodeStr, string Dt, ValueType Ty, Intrinsic IntOp> > @@ -800,6 +918,8 @@ > (Ty (NEONvduplane (Ty DPR_8:$src2), > imm:$lane)))))]> { > let isCommutable = 0; > + let NSF = NVdVnVmImmMulScalarFrm; // For disassembly. > + let NSForm = NVdVnVmImmMulScalarFrm.Value; // For disassembly. > } > > class N3VQInt op21_20, bits<4> op11_8, bit op4, > @@ -822,6 +942,8 @@ > (ResTy (NEONvduplane (OpTy DPR_VFP2:$src2), > imm:$lane)))))]> { > let isCommutable = 0; > + let NSF = NVdVnVmImmMulScalarFrm; // For disassembly. > + let NSForm = NVdVnVmImmMulScalarFrm.Value; // For disassembly. > } > class N3VQIntSL16 op21_20, bits<4> op11_8, InstrItinClass itin, > string OpcodeStr, string Dt, > @@ -834,6 +956,8 @@ > (ResTy (NEONvduplane (OpTy DPR_8:$src2), > imm:$lane)))))]> { > let isCommutable = 0; > + let NSF = NVdVnVmImmMulScalarFrm; // For disassembly. > + let NSForm = NVdVnVmImmMulScalarFrm.Value; // For disassembly. > } > > // Multiply-Add/Sub operations: single-, double- and quad-register. > @@ -864,7 +988,10 @@ > (Ty (ShOp (Ty DPR:$src1), > (Ty (MulOp DPR:$src2, > (Ty (NEONvduplane (Ty DPR_VFP2:$src3), > - imm:$lane)))))))]>; > + imm:$lane)))))))]> { > + let NSF = NVdVnVmImmMulScalarFrm; // For disassembly. > + let NSForm = NVdVnVmImmMulScalarFrm.Value; // For disassembly. > +} > class N3VDMulOpSL16 op21_20, bits<4> op11_8, InstrItinClass itin, > string OpcodeStr, string Dt, > ValueType Ty, SDNode MulOp, SDNode ShOp> > @@ -876,7 +1003,10 @@ > (Ty (ShOp (Ty DPR:$src1), > (Ty (MulOp DPR:$src2, > (Ty (NEONvduplane (Ty DPR_8:$src3), > - imm:$lane)))))))]>; > + imm:$lane)))))))]> { > + let NSF = NVdVnVmImmMulScalarFrm; // For disassembly. > + let NSForm = NVdVnVmImmMulScalarFrm.Value; // For disassembly. > +} > > class N3VQMulOp op21_20, bits<4> op11_8, bit op4, > InstrItinClass itin, string OpcodeStr, string Dt, ValueType Ty, > @@ -897,7 +1027,10 @@ > (ResTy (ShOp (ResTy QPR:$src1), > (ResTy (MulOp QPR:$src2, > (ResTy (NEONvduplane (OpTy DPR_VFP2:$src3), > - imm:$lane)))))))]>; > + imm:$lane)))))))]> { > + let NSF = NVdVnVmImmMulScalarFrm; // For disassembly. > + let NSForm = NVdVnVmImmMulScalarFrm.Value; // For disassembly. > +} > class N3VQMulOpSL16 op21_20, bits<4> op11_8, InstrItinClass itin, > string OpcodeStr, string Dt, > ValueType ResTy, ValueType OpTy, > @@ -910,7 +1043,10 @@ > (ResTy (ShOp (ResTy QPR:$src1), > (ResTy (MulOp QPR:$src2, > (ResTy (NEONvduplane (OpTy DPR_8:$src3), > - imm:$lane)))))))]>; > + imm:$lane)))))))]> { > + let NSF = NVdVnVmImmMulScalarFrm; // For disassembly. > + let NSForm = NVdVnVmImmMulScalarFrm.Value; // For disassembly. > +} > > // Neon 3-argument intrinsics, both double- and quad-register. > // The destination register is also used as the first source operand register. > @@ -996,7 +1132,10 @@ > [(set (ResTy QPR:$dst), > (ResTy (IntOp (OpTy DPR:$src1), > (OpTy (NEONvduplane (OpTy DPR_VFP2:$src2), > - imm:$lane)))))]>; > + imm:$lane)))))]> { > + let NSF = NVdVnVmImmMulScalarFrm; // For disassembly. > + let NSForm = NVdVnVmImmMulScalarFrm.Value; // For disassembly. > +} > class N3VLIntSL16 op21_20, bits<4> op11_8, > InstrItinClass itin, string OpcodeStr, string Dt, > ValueType ResTy, ValueType OpTy, Intrinsic IntOp> > @@ -1006,7 +1145,10 @@ > [(set (ResTy QPR:$dst), > (ResTy (IntOp (OpTy DPR:$src1), > (OpTy (NEONvduplane (OpTy DPR_8:$src2), > - imm:$lane)))))]>; > + imm:$lane)))))]> { > + let NSF = NVdVnVmImmMulScalarFrm; // For disassembly. > + let NSForm = NVdVnVmImmMulScalarFrm.Value; // For disassembly. > +} > > // Wide 3-register intrinsics. > class N3VWInt op21_20, bits<4> op11_8, bit op4, > @@ -1055,6 +1197,10 @@ > OpcodeStr, Dt, "$dst, $src2", "$src1 = $dst", > [(set QPR:$dst, (ResTy (IntOp (ResTy QPR:$src1), (OpTy QPR:$src2))))]>; > > +// This is a big let * in block to mark these instructions NVectorShiftFrm to > +// help the disassembler. > +let NSF = NVectorShiftFrm, NSForm = NVectorShiftFrm.Value in { > + > // Shift by immediate, > // both double- and quad-register. > class N2VDSh op11_8, bit op7, bit op4, > @@ -1072,16 +1218,6 @@ > OpcodeStr, Dt, "$dst, $src, $SIMM", "", > [(set QPR:$dst, (Ty (OpNode (Ty QPR:$src), (i32 imm:$SIMM))))]>; > > -// Long shift by immediate. > -class N2VLSh op11_8, bit op7, bit op6, bit op4, > - string OpcodeStr, string Dt, > - ValueType ResTy, ValueType OpTy, SDNode OpNode> > - : N2VImm - (outs QPR:$dst), (ins DPR:$src, i32imm:$SIMM), IIC_VSHLiD, > - OpcodeStr, Dt, "$dst, $src, $SIMM", "", > - [(set QPR:$dst, (ResTy (OpNode (OpTy DPR:$src), > - (i32 imm:$SIMM))))]>; > - > // Narrow shift by immediate. > class N2VNSh op11_8, bit op7, bit op6, bit op4, > InstrItinClass itin, string OpcodeStr, string Dt, > @@ -1124,8 +1260,26 @@ > OpcodeStr, Dt, "$dst, $src2, $SIMM", "$src1 = $dst", > [(set QPR:$dst, (Ty (ShOp QPR:$src1, QPR:$src2, (i32 imm:$SIMM))))]>; > > +} // End of "let NSF = NVectorShiftFrm, ..." > + > +// Long shift by immediate. > +class N2VLSh op11_8, bit op7, bit op6, bit op4, > + string OpcodeStr, string Dt, > + ValueType ResTy, ValueType OpTy, SDNode OpNode> > + : N2VImm + (outs QPR:$dst), (ins DPR:$src, i32imm:$SIMM), IIC_VSHLiD, > + OpcodeStr, Dt, "$dst, $src, $SIMM", "", > + [(set QPR:$dst, (ResTy (OpNode (OpTy DPR:$src), > + (i32 imm:$SIMM))))]> { > + // This has a different interpretation of the shift amount encoding than > + // NVectorShiftFrm. > + let NSF = NVectorShift2Frm; // For disassembly. > + let NSForm = NVectorShift2Frm.Value; // For disassembly. > +} > + > // Convert, with fractional bits immediate, > // both double- and quad-register. > +let NSF = NVdVmImmVCVTFrm, NSForm = NVdVmImmVCVTFrm.Value in { > class N2VCvtD op11_8, bit op7, bit op4, > string OpcodeStr, string Dt, ValueType ResTy, ValueType OpTy, > Intrinsic IntOp> > @@ -1140,6 +1294,7 @@ > (outs QPR:$dst), (ins QPR:$src, i32imm:$SIMM), IIC_VUNAQ, > OpcodeStr, Dt, "$dst, $src, $SIMM", "", > [(set QPR:$dst, (ResTy (IntOp (OpTy QPR:$src), (i32 imm:$SIMM))))]>; > +} > > //===----------------------------------------------------------------------===// > // Multiclasses > @@ -1350,6 +1505,60 @@ > v2i64, v2i64, IntOp, Commutable>; > } > > +// Same as N3VInt_QHSD, except they're for Vector Shift (Register) Instructions. > +// D:Vd M:Vm N:Vn (notice that M:Vm is the first operand) > +// This helps the disassembler. > +let NSF = NVdVnVmImmVectorShiftFrm, NSForm = NVdVnVmImmVectorShiftFrm.Value in { > +multiclass N3VInt_HS2 op11_8, bit op4, > + InstrItinClass itinD16, InstrItinClass itinD32, > + InstrItinClass itinQ16, InstrItinClass itinQ32, > + string OpcodeStr, string Dt, > + Intrinsic IntOp, bit Commutable = 0> { > + // 64-bit vector types. > + def v4i16 : N3VDInt + OpcodeStr, !strconcat(Dt, "16"), > + v4i16, v4i16, IntOp, Commutable>; > + def v2i32 : N3VDInt + OpcodeStr, !strconcat(Dt, "32"), > + v2i32, v2i32, IntOp, Commutable>; > + > + // 128-bit vector types. > + def v8i16 : N3VQInt + OpcodeStr, !strconcat(Dt, "16"), > + v8i16, v8i16, IntOp, Commutable>; > + def v4i32 : N3VQInt + OpcodeStr, !strconcat(Dt, "32"), > + v4i32, v4i32, IntOp, Commutable>; > +} > +multiclass N3VInt_QHS2 op11_8, bit op4, > + InstrItinClass itinD16, InstrItinClass itinD32, > + InstrItinClass itinQ16, InstrItinClass itinQ32, > + string OpcodeStr, string Dt, > + Intrinsic IntOp, bit Commutable = 0> > + : N3VInt_HS2 + OpcodeStr, Dt, IntOp, Commutable> { > + def v8i8 : N3VDInt + OpcodeStr, !strconcat(Dt, "8"), > + v8i8, v8i8, IntOp, Commutable>; > + def v16i8 : N3VQInt + OpcodeStr, !strconcat(Dt, "8"), > + v16i8, v16i8, IntOp, Commutable>; > +} > +multiclass N3VInt_QHSD2 op11_8, bit op4, > + InstrItinClass itinD16, InstrItinClass itinD32, > + InstrItinClass itinQ16, InstrItinClass itinQ32, > + string OpcodeStr, string Dt, > + Intrinsic IntOp, bit Commutable = 0> > + : N3VInt_QHS2 + OpcodeStr, Dt, IntOp, Commutable> { > + def v1i64 : N3VDInt + OpcodeStr, !strconcat(Dt, "64"), > + v1i64, v1i64, IntOp, Commutable>; > + def v2i64 : N3VQInt + OpcodeStr, !strconcat(Dt, "64"), > + v2i64, v2i64, IntOp, Commutable>; > +} > +} > > // Neon Narrowing 3-register vector intrinsics, > // source operand element sizes of 16, 32 and 64 bits: > @@ -1619,6 +1828,47 @@ > // imm6 = xxxxxx > } > > +// Same as N2VSh_QHSD, except the instructions have a differnt interpretation of > +// the shift amount. This helps the disassembler. > +let NSF = NVectorShift2Frm, NSForm = NVectorShift2Frm.Value in { > +multiclass N2VSh_QHSD2 op11_8, bit op4, > + InstrItinClass itin, string OpcodeStr, string Dt, > + SDNode OpNode> { > + // 64-bit vector types. > + def v8i8 : N2VDSh + OpcodeStr, !strconcat(Dt, "8"), v8i8, OpNode> { > + let Inst{21-19} = 0b001; // imm6 = 001xxx > + } > + def v4i16 : N2VDSh + OpcodeStr, !strconcat(Dt, "16"), v4i16, OpNode> { > + let Inst{21-20} = 0b01; // imm6 = 01xxxx > + } > + def v2i32 : N2VDSh + OpcodeStr, !strconcat(Dt, "32"), v2i32, OpNode> { > + let Inst{21} = 0b1; // imm6 = 1xxxxx > + } > + def v1i64 : N2VDSh + OpcodeStr, !strconcat(Dt, "64"), v1i64, OpNode>; > + // imm6 = xxxxxx > + > + // 128-bit vector types. > + def v16i8 : N2VQSh + OpcodeStr, !strconcat(Dt, "8"), v16i8, OpNode> { > + let Inst{21-19} = 0b001; // imm6 = 001xxx > + } > + def v8i16 : N2VQSh + OpcodeStr, !strconcat(Dt, "16"), v8i16, OpNode> { > + let Inst{21-20} = 0b01; // imm6 = 01xxxx > + } > + def v4i32 : N2VQSh + OpcodeStr, !strconcat(Dt, "32"), v4i32, OpNode> { > + let Inst{21} = 0b1; // imm6 = 1xxxxx > + } > + def v2i64 : N2VQSh + OpcodeStr, !strconcat(Dt, "64"), v2i64, OpNode>; > + // imm6 = xxxxxx > +} > +} > > // Neon Shift-Accumulate vector operations, > // element sizes of 8, 16, 32 and 64 bits: > @@ -1699,6 +1949,47 @@ > // imm6 = xxxxxx > } > > +// Same as N2VShIns_QHSD, except the instructions have a differnt interpretation > +// of the shift amount. This helps the disassembler. > +let NSF = NVectorShift2Frm, NSForm = NVectorShift2Frm.Value in { > +multiclass N2VShIns_QHSD2 op11_8, bit op4, > + string OpcodeStr, SDNode ShOp> { > + // 64-bit vector types. > + def v8i8 : N2VDShIns + OpcodeStr, "8", v8i8, ShOp> { > + let Inst{21-19} = 0b001; // imm6 = 001xxx > + } > + def v4i16 : N2VDShIns + OpcodeStr, "16", v4i16, ShOp> { > + let Inst{21-20} = 0b01; // imm6 = 01xxxx > + } > + def v2i32 : N2VDShIns + OpcodeStr, "32", v2i32, ShOp> { > + let Inst{21} = 0b1; // imm6 = 1xxxxx > + } > + def v1i64 : N2VDShIns + OpcodeStr, "64", v1i64, ShOp>; > + // imm6 = xxxxxx > + > + // 128-bit vector types. > + def v16i8 : N2VQShIns + OpcodeStr, "8", v16i8, ShOp> { > + let Inst{21-19} = 0b001; // imm6 = 001xxx > + } > + def v8i16 : N2VQShIns + OpcodeStr, "16", v8i16, ShOp> { > + let Inst{21-20} = 0b01; // imm6 = 01xxxx > + } > + def v4i32 : N2VQShIns + OpcodeStr, "32", v4i32, ShOp> { > + let Inst{21} = 0b1; // imm6 = 1xxxxx > + } > + def v2i64 : N2VQShIns + OpcodeStr, "64", v2i64, ShOp>; > + // imm6 = xxxxxx > +} > +} > + > // Neon Shift Long operations, > // element sizes of 8, 16, 32 bits: > multiclass N2VLSh_QHS op11_8, bit op7, bit op6, > @@ -2329,18 +2620,21 @@ > // Vector Shifts. > > // VSHL : Vector Shift > -defm VSHLs : N3VInt_QHSD<0, 0, 0b0100, 0, IIC_VSHLiD, IIC_VSHLiD, IIC_VSHLiQ, > - IIC_VSHLiQ, "vshl", "s", int_arm_neon_vshifts, 0>; > -defm VSHLu : N3VInt_QHSD<1, 0, 0b0100, 0, IIC_VSHLiD, IIC_VSHLiD, IIC_VSHLiQ, > - IIC_VSHLiQ, "vshl", "u", int_arm_neon_vshiftu, 0>; > +defm VSHLs : N3VInt_QHSD2<0,0, 0b0100, 0, IIC_VSHLiD, IIC_VSHLiD, IIC_VSHLiQ, > + IIC_VSHLiQ, "vshl", "s", int_arm_neon_vshifts, 0>; > +defm VSHLu : N3VInt_QHSD2<1,0, 0b0100, 0, IIC_VSHLiD, IIC_VSHLiD, IIC_VSHLiQ, > + IIC_VSHLiQ, "vshl", "u", int_arm_neon_vshiftu, 0>; > // VSHL : Vector Shift Left (Immediate) > -defm VSHLi : N2VSh_QHSD<0, 1, 0b0101, 1, IIC_VSHLiD, "vshl", "i", NEONvshl>; > +// (disassembly note: this has a different interpretation of the shift amont) > +defm VSHLi : N2VSh_QHSD2<0, 1, 0b0101, 1, IIC_VSHLiD, "vshl", "i", NEONvshl>; > // VSHR : Vector Shift Right (Immediate) > defm VSHRs : N2VSh_QHSD<0, 1, 0b0000, 1, IIC_VSHLiD, "vshr", "s", NEONvshrs>; > defm VSHRu : N2VSh_QHSD<1, 1, 0b0000, 1, IIC_VSHLiD, "vshr", "u", NEONvshru>; > > // VSHLL : Vector Shift Left Long > +// (disassembly note: this has a different interpretation of the shift amont) > defm VSHLLs : N2VLSh_QHS<0, 1, 0b1010, 0, 0, 1, "vshll", "s", NEONvshlls>; > +// (disassembly note: this has a different interpretation of the shift amont) > defm VSHLLu : N2VLSh_QHS<1, 1, 0b1010, 0, 0, 1, "vshll", "u", NEONvshllu>; > > // VSHLL : Vector Shift Left Long (with maximum shift count) > @@ -2350,6 +2644,8 @@ > : N2VLSh ResTy, OpTy, OpNode> { > let Inst{21-16} = op21_16; > + let NSF = NVdVmImmVSHLLFrm; // For disassembly. > + let NSForm = NVdVmImmVSHLLFrm.Value; // For disassembly. > } > def VSHLLi8 : N2VLShMax<1, 1, 0b110010, 0b0011, 0, 0, 0, "vshll", "i8", > v8i16, v8i8, NEONvshlli>; > @@ -2363,10 +2659,10 @@ > NEONvshrn>; > > // VRSHL : Vector Rounding Shift > -defm VRSHLs : N3VInt_QHSD<0,0,0b0101,0, IIC_VSHLi4D, IIC_VSHLi4D, IIC_VSHLi4Q, > - IIC_VSHLi4Q, "vrshl", "s", int_arm_neon_vrshifts,0>; > -defm VRSHLu : N3VInt_QHSD<1,0,0b0101,0, IIC_VSHLi4D, IIC_VSHLi4D, IIC_VSHLi4Q, > - IIC_VSHLi4Q, "vrshl", "u", int_arm_neon_vrshiftu,0>; > +defm VRSHLs : N3VInt_QHSD2<0,0,0b0101,0,IIC_VSHLi4D, IIC_VSHLi4D, IIC_VSHLi4Q, > + IIC_VSHLi4Q,"vrshl", "s", int_arm_neon_vrshifts,0>; > +defm VRSHLu : N3VInt_QHSD2<1,0,0b0101,0,IIC_VSHLi4D, IIC_VSHLi4D, IIC_VSHLi4Q, > + IIC_VSHLi4Q,"vrshl", "u", int_arm_neon_vrshiftu,0>; > // VRSHR : Vector Rounding Shift Right > defm VRSHRs : N2VSh_QHSD<0,1,0b0010,1, IIC_VSHLi4D, "vrshr", "s", NEONvrshrs>; > defm VRSHRu : N2VSh_QHSD<1,1,0b0010,1, IIC_VSHLi4D, "vrshr", "u", NEONvrshru>; > @@ -2376,15 +2672,18 @@ > NEONvrshrn>; > > // VQSHL : Vector Saturating Shift > -defm VQSHLs : N3VInt_QHSD<0,0,0b0100,1, IIC_VSHLi4D, IIC_VSHLi4D, IIC_VSHLi4Q, > - IIC_VSHLi4Q, "vqshl", "s", int_arm_neon_vqshifts,0>; > -defm VQSHLu : N3VInt_QHSD<1,0,0b0100,1, IIC_VSHLi4D, IIC_VSHLi4D, IIC_VSHLi4Q, > - IIC_VSHLi4Q, "vqshl", "u", int_arm_neon_vqshiftu,0>; > +defm VQSHLs : N3VInt_QHSD2<0,0,0b0100,1,IIC_VSHLi4D, IIC_VSHLi4D, IIC_VSHLi4Q, > + IIC_VSHLi4Q, "vqshl", "s", int_arm_neon_vqshifts,0>; > +defm VQSHLu : N3VInt_QHSD2<1,0,0b0100,1,IIC_VSHLi4D, IIC_VSHLi4D, IIC_VSHLi4Q, > + IIC_VSHLi4Q, "vqshl", "u", int_arm_neon_vqshiftu,0>; > // VQSHL : Vector Saturating Shift Left (Immediate) > -defm VQSHLsi : N2VSh_QHSD<0,1,0b0111,1, IIC_VSHLi4D, "vqshl", "s", NEONvqshls>; > -defm VQSHLui : N2VSh_QHSD<1,1,0b0111,1, IIC_VSHLi4D, "vqshl", "u", NEONvqshlu>; > +// (disassembly note: this has a different interpretation of the shift amont) > +defm VQSHLsi : N2VSh_QHSD2<0,1,0b0111,1, IIC_VSHLi4D, "vqshl", "s", NEONvqshls>; > +// (disassembly note: this has a different interpretation of the shift amont) > +defm VQSHLui : N2VSh_QHSD2<1,1,0b0111,1, IIC_VSHLi4D, "vqshl", "u", NEONvqshlu>; > // VQSHLU : Vector Saturating Shift Left (Immediate, Unsigned) > -defm VQSHLsu : N2VSh_QHSD<1,1,0b0110,1, IIC_VSHLi4D, "vqshlu","s",NEONvqshlsu>; > +// (disassembly note: this has a different interpretation of the shift amont) > +defm VQSHLsu : N2VSh_QHSD2<1,1,0b0110,1, IIC_VSHLi4D, "vqshlu","s",NEONvqshlsu>; > > // VQSHRN : Vector Saturating Shift Right and Narrow > defm VQSHRNs : N2VNSh_HSD<0, 1, 0b1001, 0, 0, 1, IIC_VSHLi4D, "vqshrn", "s", > @@ -2397,12 +2696,12 @@ > NEONvqshrnsu>; > > // VQRSHL : Vector Saturating Rounding Shift > -defm VQRSHLs : N3VInt_QHSD<0,0,0b0101,1, IIC_VSHLi4D, IIC_VSHLi4D, IIC_VSHLi4Q, > - IIC_VSHLi4Q, "vqrshl", "s", > - int_arm_neon_vqrshifts, 0>; > -defm VQRSHLu : N3VInt_QHSD<1,0,0b0101,1, IIC_VSHLi4D, IIC_VSHLi4D, IIC_VSHLi4Q, > - IIC_VSHLi4Q, "vqrshl", "u", > - int_arm_neon_vqrshiftu, 0>; > +defm VQRSHLs : N3VInt_QHSD2<0,0,0b0101,1, IIC_VSHLi4D, IIC_VSHLi4D, IIC_VSHLi4Q, > + IIC_VSHLi4Q, "vqrshl", "s", > + int_arm_neon_vqrshifts, 0>; > +defm VQRSHLu : N3VInt_QHSD2<1,0,0b0101,1, IIC_VSHLi4D, IIC_VSHLi4D, IIC_VSHLi4Q, > + IIC_VSHLi4Q, "vqrshl", "u", > + int_arm_neon_vqrshiftu, 0>; > > // VQRSHRN : Vector Saturating Rounding Shift Right and Narrow > defm VQRSHRNs : N2VNSh_HSD<0, 1, 0b1001, 0, 1, 1, IIC_VSHLi4D, "vqrshrn", "s", > @@ -2422,7 +2721,8 @@ > defm VRSRAu : N2VShAdd_QHSD<1, 1, 0b0011, 1, "vrsra", "u", NEONvrshru>; > > // VSLI : Vector Shift Left and Insert > -defm VSLI : N2VShIns_QHSD<1, 1, 0b0101, 1, "vsli", NEONvsli>; > +// (disassembly note: this has a different interpretation of the shift amont) > +defm VSLI : N2VShIns_QHSD2<1, 1, 0b0101, 1, "vsli", NEONvsli>; > // VSRI : Vector Shift Right and Insert > defm VSRI : N2VShIns_QHSD<1, 1, 0b0100, 1, "vsri", NEONvsri>; > > @@ -2518,10 +2818,13 @@ > > // VMOV : Vector Move (Register) > > +// Mark these instructions as 2-register instructions to help the disassembler. > +let NSF = NVdVmImmFrm, NSForm = NVdVmImmFrm.Value in { > def VMOVDneon: N3VX<0, 0, 0b10, 0b0001, 0, 1, (outs DPR:$dst), (ins DPR:$src), > IIC_VMOVD, "vmov", "$dst, $src", "", []>; > def VMOVQ : N3VX<0, 0, 0b10, 0b0001, 1, 1, (outs QPR:$dst), (ins QPR:$src), > IIC_VMOVD, "vmov", "$dst, $src", "", []>; > +} > > // VMOV : Vector Move (Immediate) > > @@ -2762,6 +3065,7 @@ > > // VDUP : Vector Duplicate Lane (from scalar to all elements) > > +let NSF = NVdVmImmVDupLaneFrm, NSForm = NVdVmImmVDupLaneFrm.Value in { > class VDUPLND op19_18, bits<2> op17_16, > string OpcodeStr, string Dt, ValueType Ty> > : N2V<0b11, 0b11, op19_18, op17_16, 0b11000, 0, 0, > @@ -2775,6 +3079,7 @@ > (outs QPR:$dst), (ins DPR:$src, nohash_imm:$lane), IIC_VMOVD, > OpcodeStr, Dt, "$dst, $src[$lane]", "", > [(set QPR:$dst, (ResTy (NEONvduplane (OpTy DPR:$src), imm:$lane)))]>; > +} > > // Inst{19-16} is partially specified depending on the element size. > > @@ -2843,24 +3148,37 @@ > > // Vector Conversions. > > +let NSF = NVdVmImmVCVTFrm, NSForm = NVdVmImmVCVTFrm.Value in { > +class N2VDX op24_23, bits<2> op21_20, bits<2> op19_18, > + bits<2> op17_16, bits<5> op11_7, bit op4, string OpcodeStr, > + string Dt, ValueType ResTy, ValueType OpTy, SDNode OpNode> > + : N2VD + ResTy, OpTy, OpNode>; > +class N2VQX op24_23, bits<2> op21_20, bits<2> op19_18, > + bits<2> op17_16, bits<5> op11_7, bit op4, string OpcodeStr, > + string Dt, ValueType ResTy, ValueType OpTy, SDNode OpNode> > + : N2VQ + ResTy, OpTy, OpNode>; > +} > + > // VCVT : Vector Convert Between Floating-Point and Integers > -def VCVTf2sd : N2VD<0b11, 0b11, 0b10, 0b11, 0b01110, 0, "vcvt", "s32.f32", > - v2i32, v2f32, fp_to_sint>; > -def VCVTf2ud : N2VD<0b11, 0b11, 0b10, 0b11, 0b01111, 0, "vcvt", "u32.f32", > - v2i32, v2f32, fp_to_uint>; > -def VCVTs2fd : N2VD<0b11, 0b11, 0b10, 0b11, 0b01100, 0, "vcvt", "f32.s32", > - v2f32, v2i32, sint_to_fp>; > -def VCVTu2fd : N2VD<0b11, 0b11, 0b10, 0b11, 0b01101, 0, "vcvt", "f32.u32", > - v2f32, v2i32, uint_to_fp>; > - > -def VCVTf2sq : N2VQ<0b11, 0b11, 0b10, 0b11, 0b01110, 0, "vcvt", "s32.f32", > - v4i32, v4f32, fp_to_sint>; > -def VCVTf2uq : N2VQ<0b11, 0b11, 0b10, 0b11, 0b01111, 0, "vcvt", "u32.f32", > - v4i32, v4f32, fp_to_uint>; > -def VCVTs2fq : N2VQ<0b11, 0b11, 0b10, 0b11, 0b01100, 0, "vcvt", "f32.s32", > - v4f32, v4i32, sint_to_fp>; > -def VCVTu2fq : N2VQ<0b11, 0b11, 0b10, 0b11, 0b01101, 0, "vcvt", "f32.u32", > - v4f32, v4i32, uint_to_fp>; > +def VCVTf2sd : N2VDX<0b11, 0b11, 0b10, 0b11, 0b01110, 0, "vcvt", "s32.f32", > + v2i32, v2f32, fp_to_sint>; > +def VCVTf2ud : N2VDX<0b11, 0b11, 0b10, 0b11, 0b01111, 0, "vcvt", "u32.f32", > + v2i32, v2f32, fp_to_uint>; > +def VCVTs2fd : N2VDX<0b11, 0b11, 0b10, 0b11, 0b01100, 0, "vcvt", "f32.s32", > + v2f32, v2i32, sint_to_fp>; > +def VCVTu2fd : N2VDX<0b11, 0b11, 0b10, 0b11, 0b01101, 0, "vcvt", "f32.u32", > + v2f32, v2i32, uint_to_fp>; > + > +def VCVTf2sq : N2VQX<0b11, 0b11, 0b10, 0b11, 0b01110, 0, "vcvt", "s32.f32", > + v4i32, v4f32, fp_to_sint>; > +def VCVTf2uq : N2VQX<0b11, 0b11, 0b10, 0b11, 0b01111, 0, "vcvt", "u32.f32", > + v4i32, v4f32, fp_to_uint>; > +def VCVTs2fq : N2VQX<0b11, 0b11, 0b10, 0b11, 0b01100, 0, "vcvt", "f32.s32", > + v4f32, v4i32, sint_to_fp>; > +def VCVTu2fq : N2VQX<0b11, 0b11, 0b10, 0b11, 0b01101, 0, "vcvt", "f32.u32", > + v4f32, v4i32, uint_to_fp>; > > // VCVT : Vector Convert Between Floating-Point and Fixed-Point. > def VCVTf2xsd : N2VCvtD<0, 1, 0b1111, 0, 1, "vcvt", "s32.f32", > @@ -2945,6 +3263,8 @@ > > // VEXT : Vector Extract > > +let NSF = NVdVnVmImmVectorExtractFrm, > + NSForm = NVdVnVmImmVectorExtractFrm.Value in { > class VEXTd > : N3V<0,1,0b11,{?,?,?,?},0,0, (outs DPR:$dst), > (ins DPR:$lhs, DPR:$rhs, i32imm:$index), IIC_VEXTD, > @@ -2958,6 +3278,7 @@ > OpcodeStr, Dt, "$dst, $lhs, $rhs, $index", "", > [(set QPR:$dst, (Ty (NEONvext (Ty QPR:$lhs), > (Ty QPR:$rhs), imm:$index)))]>; > +} > > def VEXTd8 : VEXTd<"vext", "8", v8i8>; > def VEXTd16 : VEXTd<"vext", "16", v4i16>; > @@ -3001,6 +3322,8 @@ > > // Vector Table Lookup and Table Extension. > > +let NSF = VTBLFrm, NSForm = VTBLFrm.Value in { > + > // VTBL : Vector Table Lookup > def VTBL1 > : N3V<1,1,0b11,0b1000,0,0, (outs DPR:$dst), > @@ -3057,6 +3380,8 @@ > DPR:$tbl2, DPR:$tbl3, DPR:$tbl4, DPR:$src)))]>; > } // hasExtraSrcRegAllocReq = 1 > > +} // End of "let NSF = VTBLFrm, ..." > + > //===----------------------------------------------------------------------===// > // NEON instructions for single-precision FP math > //===----------------------------------------------------------------------===// > > Modified: llvm/trunk/lib/Target/ARM/AsmPrinter/ARMAsmPrinter.cpp > URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Target/ARM/AsmPrinter/ARMAsmPrinter.cpp?rev=98637&r1=98636&r2=98637&view=diff > ============================================================================== > --- llvm/trunk/lib/Target/ARM/AsmPrinter/ARMAsmPrinter.cpp (original) > +++ llvm/trunk/lib/Target/ARM/AsmPrinter/ARMAsmPrinter.cpp Tue Mar 16 11:36:54 2010 > @@ -120,7 +120,7 @@ > void printT2AddrModeImm8Operand(const MachineInstr *MI, int OpNum); > void printT2AddrModeImm8s4Operand(const MachineInstr *MI, int OpNum); > void printT2AddrModeImm8OffsetOperand(const MachineInstr *MI, int OpNum); > - void printT2AddrModeImm8s4OffsetOperand(const MachineInstr *MI, int OpNum) {} > + void printT2AddrModeImm8s4OffsetOperand(const MachineInstr *MI, int OpNum); > void printT2AddrModeSoRegOperand(const MachineInstr *MI, int OpNum); > > void printCPSOptionOperand(const MachineInstr *MI, int OpNum) {} > @@ -431,16 +431,16 @@ > O << "[" << getRegisterName(MO1.getReg()); > > if (!MO2.getReg()) { > - if (ARM_AM::getAM2Offset(MO3.getImm())) // Don't print +0. > + if (ARM_AM::getAM2Offset(MO3.getImm())) // Don't print +0. > O << ", #" > - << (char)ARM_AM::getAM2Op(MO3.getImm()) > + << ARM_AM::getAddrOpcStr(ARM_AM::getAM2Op(MO3.getImm())) > << ARM_AM::getAM2Offset(MO3.getImm()); > O << "]"; > return; > } > > O << ", " > - << (char)ARM_AM::getAM2Op(MO3.getImm()) > + << ARM_AM::getAddrOpcStr(ARM_AM::getAM2Op(MO3.getImm())) > << getRegisterName(MO2.getReg()); > > if (unsigned ShImm = ARM_AM::getAM2Offset(MO3.getImm())) > @@ -458,12 +458,12 @@ > unsigned ImmOffs = ARM_AM::getAM2Offset(MO2.getImm()); > assert(ImmOffs && "Malformed indexed load / store!"); > O << "#" > - << (char)ARM_AM::getAM2Op(MO2.getImm()) > + << ARM_AM::getAddrOpcStr(ARM_AM::getAM2Op(MO2.getImm())) > << ImmOffs; > return; > } > > - O << (char)ARM_AM::getAM2Op(MO2.getImm()) > + O << ARM_AM::getAddrOpcStr(ARM_AM::getAM2Op(MO2.getImm())) > << getRegisterName(MO1.getReg()); > > if (unsigned ShImm = ARM_AM::getAM2Offset(MO2.getImm())) > @@ -490,7 +490,7 @@ > > if (unsigned ImmOffs = ARM_AM::getAM3Offset(MO3.getImm())) > O << ", #" > - << (char)ARM_AM::getAM3Op(MO3.getImm()) > + << ARM_AM::getAddrOpcStr(ARM_AM::getAM3Op(MO3.getImm())) > << ImmOffs; > O << "]"; > } > @@ -508,7 +508,7 @@ > unsigned ImmOffs = ARM_AM::getAM3Offset(MO2.getImm()); > assert(ImmOffs && "Malformed indexed load / store!"); > O << "#" > - << (char)ARM_AM::getAM3Op(MO2.getImm()) > + << ARM_AM::getAddrOpcStr(ARM_AM::getAM3Op(MO2.getImm())) > << ImmOffs; > } > > @@ -558,7 +558,7 @@ > > if (unsigned ImmOffs = ARM_AM::getAM5Offset(MO2.getImm())) { > O << ", #" > - << (char)ARM_AM::getAM5Op(MO2.getImm()) > + << ARM_AM::getAddrOpcStr(ARM_AM::getAM5Op(MO2.getImm())) > << ImmOffs*4; > } > O << "]"; > @@ -594,7 +594,7 @@ > > const MachineOperand &MO1 = MI->getOperand(Op); > assert(TargetRegisterInfo::isPhysicalRegister(MO1.getReg())); > - O << "[pc, +" << getRegisterName(MO1.getReg()) << "]"; > + O << "[pc, " << getRegisterName(MO1.getReg()) << "]"; > } > > void > @@ -617,10 +617,11 @@ > ARMAsmPrinter::printThumbITMask(const MachineInstr *MI, int Op) { > // (3 - the number of trailing zeros) is the number of then / else. > unsigned Mask = MI->getOperand(Op).getImm(); > + unsigned CondBit0 = Mask >> 4 & 1; > unsigned NumTZ = CountTrailingZeros_32(Mask); > assert(NumTZ <= 3 && "Invalid IT mask!"); > for (unsigned Pos = 3, e = NumTZ; Pos > e; --Pos) { > - bool T = (Mask & (1 << Pos)) == 0; > + bool T = ((Mask >> Pos) & 1) == CondBit0; > if (T) > O << 't'; > else > @@ -652,7 +653,7 @@ > if (MO3.getReg()) > O << ", " << getRegisterName(MO3.getReg()); > else if (unsigned ImmOffs = MO2.getImm()) > - O << ", #+" << ImmOffs * Scale; > + O << ", #" << ImmOffs * Scale; > O << "]"; > } > > @@ -674,7 +675,7 @@ > const MachineOperand &MO2 = MI->getOperand(Op+1); > O << "[" << getRegisterName(MO1.getReg()); > if (unsigned ImmOffs = MO2.getImm()) > - O << ", #+" << ImmOffs*4; > + O << ", #" << ImmOffs*4; > O << "]"; > } > > @@ -710,7 +711,7 @@ > > unsigned OffImm = MO2.getImm(); > if (OffImm) // Don't print +0. > - O << ", #+" << OffImm; > + O << ", #" << OffImm; > O << "]"; > } > > @@ -726,7 +727,7 @@ > if (OffImm < 0) > O << ", #-" << -OffImm; > else if (OffImm > 0) > - O << ", #+" << OffImm; > + O << ", #" << OffImm; > O << "]"; > } > > @@ -742,7 +743,7 @@ > if (OffImm < 0) > O << ", #-" << -OffImm * 4; > else if (OffImm > 0) > - O << ", #+" << OffImm * 4; > + O << ", #" << OffImm * 4; > O << "]"; > } > > @@ -754,7 +755,18 @@ > if (OffImm < 0) > O << "#-" << -OffImm; > else if (OffImm > 0) > - O << "#+" << OffImm; > + O << "#" << OffImm; > +} > + > +void ARMAsmPrinter::printT2AddrModeImm8s4OffsetOperand(const MachineInstr *MI, > + int OpNum) { > + const MachineOperand &MO1 = MI->getOperand(OpNum); > + int32_t OffImm = (int32_t)MO1.getImm() / 4; > + // Don't print +0. > + if (OffImm < 0) > + O << "#-" << -OffImm * 4; > + else if (OffImm > 0) > + O << "#" << OffImm * 4; > } > > void ARMAsmPrinter::printT2AddrModeSoRegOperand(const MachineInstr *MI, > > Modified: llvm/trunk/lib/Target/ARM/AsmPrinter/ARMInstPrinter.cpp > URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Target/ARM/AsmPrinter/ARMInstPrinter.cpp?rev=98637&r1=98636&r2=98637&view=diff > ============================================================================== > --- llvm/trunk/lib/Target/ARM/AsmPrinter/ARMInstPrinter.cpp (original) > +++ llvm/trunk/lib/Target/ARM/AsmPrinter/ARMInstPrinter.cpp Tue Mar 16 11:36:54 2010 > @@ -28,7 +28,165 @@ > #undef MachineInstr > #undef ARMAsmPrinter > > -void ARMInstPrinter::printInst(const MCInst *MI) { printInstruction(MI); } > +static unsigned NextReg(unsigned Reg) { > + switch (Reg) { > + case ARM::D0: > + return ARM::D1; > + case ARM::D1: > + return ARM::D2; > + case ARM::D2: > + return ARM::D3; > + case ARM::D3: > + return ARM::D4; > + case ARM::D4: > + return ARM::D5; > + case ARM::D5: > + return ARM::D6; > + case ARM::D6: > + return ARM::D7; > + case ARM::D7: > + return ARM::D8; > + case ARM::D8: > + return ARM::D9; > + case ARM::D9: > + return ARM::D10; > + case ARM::D10: > + return ARM::D11; > + case ARM::D11: > + return ARM::D12; > + case ARM::D12: > + return ARM::D13; > + case ARM::D13: > + return ARM::D14; > + case ARM::D14: > + return ARM::D15; > + case ARM::D15: > + return ARM::D16; > + case ARM::D16: > + return ARM::D17; > + case ARM::D17: > + return ARM::D18; > + case ARM::D18: > + return ARM::D19; > + case ARM::D19: > + return ARM::D20; > + case ARM::D20: > + return ARM::D21; > + case ARM::D21: > + return ARM::D22; > + case ARM::D22: > + return ARM::D23; > + case ARM::D23: > + return ARM::D24; > + case ARM::D24: > + return ARM::D25; > + case ARM::D25: > + return ARM::D26; > + case ARM::D26: > + return ARM::D27; > + case ARM::D27: > + return ARM::D28; > + case ARM::D28: > + return ARM::D29; > + case ARM::D29: > + return ARM::D30; > + case ARM::D30: > + return ARM::D31; > + > + default: > + assert(0 && "Unexpected register enum"); > + } > +} > + > +void ARMInstPrinter::printInst(const MCInst *MI) { > + // Check for MOVs and print canonical forms, instead. > + if (MI->getOpcode() == ARM::MOVs) { > + const MCOperand &Dst = MI->getOperand(0); > + const MCOperand &MO1 = MI->getOperand(1); > + const MCOperand &MO2 = MI->getOperand(2); > + const MCOperand &MO3 = MI->getOperand(3); > + > + O << '\t' << ARM_AM::getShiftOpcStr(ARM_AM::getSORegShOp(MO3.getImm())); > + printSBitModifierOperand(MI, 6); > + printPredicateOperand(MI, 4); > + > + O << '\t' << getRegisterName(Dst.getReg()) > + << ", " << getRegisterName(MO1.getReg()); > + > + if (ARM_AM::getSORegShOp(MO3.getImm()) == ARM_AM::rrx) > + return; > + > + O << ", "; > + > + if (MO2.getReg()) { > + O << getRegisterName(MO2.getReg()); > + assert(ARM_AM::getSORegOffset(MO3.getImm()) == 0); > + } else { > + O << "#" << ARM_AM::getSORegOffset(MO3.getImm()); > + } > + return; > + } > + > + // A8.6.123 PUSH > + if ((MI->getOpcode() == ARM::STM || MI->getOpcode() == ARM::t2STM_UPD) && > + MI->getOperand(0).getReg() == ARM::SP) { > + const unsigned IdxOffset = MI->getOpcode() == ARM::STM ? 0 : 1; > + const MCOperand &MO1 = MI->getOperand(IdxOffset + 1); > + if (ARM_AM::getAM4WBFlag(MO1.getImm()) && > + ARM_AM::getAM4SubMode(MO1.getImm()) == ARM_AM::db) { > + O << '\t' << "push"; > + printPredicateOperand(MI, IdxOffset + 2); > + O << '\t'; > + printRegisterList(MI, IdxOffset + 4); > + return; > + } > + } > + > + // A8.6.122 POP > + if ((MI->getOpcode() == ARM::LDM || MI->getOpcode() == ARM::t2LDM_UPD) && > + MI->getOperand(0).getReg() == ARM::SP) { > + const unsigned IdxOffset = MI->getOpcode() == ARM::LDM ? 0 : 1; > + const MCOperand &MO1 = MI->getOperand(IdxOffset + 1); > + if (ARM_AM::getAM4WBFlag(MO1.getImm()) && > + ARM_AM::getAM4SubMode(MO1.getImm()) == ARM_AM::ia) { > + O << '\t' << "pop"; > + printPredicateOperand(MI, IdxOffset + 2); > + O << '\t'; > + printRegisterList(MI, IdxOffset + 4); > + return; > + } > + } > + > + // A8.6.355 VPUSH > + if ((MI->getOpcode() == ARM::VSTMS || MI->getOpcode() == ARM::VSTMD) && > + MI->getOperand(0).getReg() == ARM::SP) { > + const MCOperand &MO1 = MI->getOperand(1); > + if (ARM_AM::getAM5WBFlag(MO1.getImm()) && > + ARM_AM::getAM5SubMode(MO1.getImm()) == ARM_AM::db) { > + O << '\t' << "vpush"; > + printPredicateOperand(MI, 2); > + O << '\t'; > + printRegisterList(MI, 4); > + return; > + } > + } > + > + // A8.6.354 VPOP > + if ((MI->getOpcode() == ARM::VLDMS || MI->getOpcode() == ARM::VLDMD) && > + MI->getOperand(0).getReg() == ARM::SP) { > + const MCOperand &MO1 = MI->getOperand(1); > + if (ARM_AM::getAM5WBFlag(MO1.getImm()) && > + ARM_AM::getAM5SubMode(MO1.getImm()) == ARM_AM::ia) { > + O << '\t' << "vpop"; > + printPredicateOperand(MI, 2); > + O << '\t'; > + printRegisterList(MI, 4); > + return; > + } > + } > + > + printInstruction(MI); > + } > > void ARMInstPrinter::printOperand(const MCInst *MI, unsigned OpNo, > const char *Modifier) { > @@ -36,6 +194,9 @@ > if (Op.isReg()) { > unsigned Reg = Op.getReg(); > if (Modifier && strcmp(Modifier, "dregpair") == 0) { > + O << '{' << getRegisterName(Reg) << ", " > + << getRegisterName(NextReg(Reg)) << '}'; > +#if 0 > // FIXME: Breaks e.g. ARM/vmul.ll. > assert(0); > /* > @@ -44,6 +205,7 @@ > O << '{' > << getRegisterName(DRegLo) << ',' << getRegisterName(DRegHi) > << '}';*/ > +#endif > } else if (Modifier && strcmp(Modifier, "lane") == 0) { > assert(0); > /* > @@ -56,7 +218,9 @@ > O << getRegisterName(Reg); > } > } else if (Op.isImm()) { > - assert((Modifier == 0 || Modifier[0] == 0) && "No modifiers supported"); > + bool isCallOp = Modifier && !strcmp(Modifier, "call"); > + assert(isCallOp || > + ((Modifier == 0 || Modifier[0] == 0) && "No modifiers supported")); > O << '#' << Op.getImm(); > } else { > assert((Modifier == 0 || Modifier[0] == 0) && "No modifiers supported"); > @@ -142,17 +306,17 @@ > O << "[" << getRegisterName(MO1.getReg()); > > if (!MO2.getReg()) { > - if (ARM_AM::getAM2Offset(MO3.getImm())) // Don't print +0. > + if (ARM_AM::getAM2Offset(MO3.getImm())) // Don't print +0. > O << ", #" > - << (char)ARM_AM::getAM2Op(MO3.getImm()) > - << ARM_AM::getAM2Offset(MO3.getImm()); > + << ARM_AM::getAddrOpcStr(ARM_AM::getAM2Op(MO3.getImm())) > + << ARM_AM::getAM2Offset(MO3.getImm()); > O << "]"; > return; > } > > O << ", " > - << (char)ARM_AM::getAM2Op(MO3.getImm()) > - << getRegisterName(MO2.getReg()); > + << ARM_AM::getAddrOpcStr(ARM_AM::getAM2Op(MO3.getImm())) > + << getRegisterName(MO2.getReg()); > > if (unsigned ShImm = ARM_AM::getAM2Offset(MO3.getImm())) > O << ", " > @@ -169,11 +333,14 @@ > if (!MO1.getReg()) { > unsigned ImmOffs = ARM_AM::getAM2Offset(MO2.getImm()); > assert(ImmOffs && "Malformed indexed load / store!"); > - O << '#' << (char)ARM_AM::getAM2Op(MO2.getImm()) << ImmOffs; > + O << '#' > + << ARM_AM::getAddrOpcStr(ARM_AM::getAM2Op(MO2.getImm())) > + << ImmOffs; > return; > } > > - O << (char)ARM_AM::getAM2Op(MO2.getImm()) << getRegisterName(MO1.getReg()); > + O << ARM_AM::getAddrOpcStr(ARM_AM::getAM2Op(MO2.getImm())) > + << getRegisterName(MO1.getReg()); > > if (unsigned ShImm = ARM_AM::getAM2Offset(MO2.getImm())) > O << ", " > @@ -196,8 +363,8 @@ > > if (unsigned ImmOffs = ARM_AM::getAM3Offset(MO3.getImm())) > O << ", #" > - << (char)ARM_AM::getAM3Op(MO3.getImm()) > - << ImmOffs; > + << ARM_AM::getAddrOpcStr(ARM_AM::getAM3Op(MO3.getImm())) > + << ImmOffs; > O << ']'; > } > > @@ -214,9 +381,9 @@ > > unsigned ImmOffs = ARM_AM::getAM3Offset(MO2.getImm()); > assert(ImmOffs && "Malformed indexed load / store!"); > - O << "#" > - << (char)ARM_AM::getAM3Op(MO2.getImm()) > - << ImmOffs; > + O << '#' > + << ARM_AM::getAddrOpcStr(ARM_AM::getAM3Op(MO2.getImm())) > + << ImmOffs; > } > > > @@ -264,7 +431,7 @@ > > if (unsigned ImmOffs = ARM_AM::getAM5Offset(MO2.getImm())) { > O << ", #" > - << (char)ARM_AM::getAM5Op(MO2.getImm()) > + << ARM_AM::getAddrOpcStr(ARM_AM::getAM5Op(MO2.getImm())) > << ImmOffs*4; > } > O << "]"; > @@ -303,14 +470,56 @@ > > void ARMInstPrinter::printRegisterList(const MCInst *MI, unsigned OpNum) { > O << "{"; > - // Always skip the first operand, it's the optional (and implicit writeback). > - for (unsigned i = OpNum+1, e = MI->getNumOperands(); i != e; ++i) { > - if (i != OpNum+1) O << ", "; > + for (unsigned i = OpNum, e = MI->getNumOperands(); i != e; ++i) { > + if (i != OpNum) O << ", "; > O << getRegisterName(MI->getOperand(i).getReg()); > } > O << "}"; > } > > +void ARMInstPrinter::printCPSOptionOperand(const MCInst *MI, unsigned OpNum) { > + const MCOperand &Op = MI->getOperand(OpNum); > + unsigned option = Op.getImm(); > + unsigned mode = option & 31; > + bool changemode = option >> 5 & 1; > + unsigned AIF = option >> 6 & 7; > + unsigned imod = option >> 9 & 3; > + if (imod == 2) > + O << "ie"; > + else if (imod == 3) > + O << "id"; > + O << '\t'; > + if (imod > 1) { > + if (AIF & 4) O << 'a'; > + if (AIF & 2) O << 'i'; > + if (AIF & 1) O << 'f'; > + if (AIF > 0 && changemode) O << ", "; > + } > + if (changemode) > + O << '#' << mode; > +} > + > +void ARMInstPrinter::printMSRMaskOperand(const MCInst *MI, unsigned OpNum) { > + const MCOperand &Op = MI->getOperand(OpNum); > + unsigned Mask = Op.getImm(); > + if (Mask) { > + O << '_'; > + if (Mask & 8) O << 'f'; > + if (Mask & 4) O << 's'; > + if (Mask & 2) O << 'x'; > + if (Mask & 1) O << 'c'; > + } > +} > + > +void ARMInstPrinter::printNegZeroOperand(const MCInst *MI, unsigned OpNum){ > + const MCOperand &Op = MI->getOperand(OpNum); > + O << '#'; > + if (Op.getImm() < 0) > + O << '-' << (-Op.getImm() - 1); > + else > + O << Op.getImm(); > +} > + > void ARMInstPrinter::printPredicateOperand(const MCInst *MI, unsigned OpNum) { > ARMCC::CondCodes CC = (ARMCC::CondCodes)MI->getOperand(OpNum).getImm(); > if (CC != ARMCC::AL) > @@ -352,3 +561,191 @@ > void ARMInstPrinter::printThumbS4ImmOperand(const MCInst *MI, unsigned OpNum) { > O << "#" << MI->getOperand(OpNum).getImm() * 4; > } > + > +void ARMInstPrinter::printThumbITMask(const MCInst *MI, unsigned OpNum) { > + // (3 - the number of trailing zeros) is the number of then / else. > + unsigned Mask = MI->getOperand(OpNum).getImm(); > + unsigned CondBit0 = Mask >> 4 & 1; > + unsigned NumTZ = CountTrailingZeros_32(Mask); > + assert(NumTZ <= 3 && "Invalid IT mask!"); > + for (unsigned Pos = 3, e = NumTZ; Pos > e; --Pos) { > + bool T = ((Mask >> Pos) & 1) == CondBit0; > + if (T) > + O << 't'; > + else > + O << 'e'; > + } > +} > + > +void ARMInstPrinter::printThumbAddrModeRROperand(const MCInst *MI, unsigned Op) > +{ > + const MCOperand &MO1 = MI->getOperand(Op); > + const MCOperand &MO2 = MI->getOperand(Op+1); > + O << "[" << getRegisterName(MO1.getReg()); > + O << ", " << getRegisterName(MO2.getReg()) << "]"; > +} > + > +void ARMInstPrinter::printThumbAddrModeRI5Operand(const MCInst *MI, unsigned Op, > + unsigned Scale) { > + const MCOperand &MO1 = MI->getOperand(Op); > + const MCOperand &MO2 = MI->getOperand(Op+1); > + const MCOperand &MO3 = MI->getOperand(Op+2); > + > + if (!MO1.isReg()) { // FIXME: This is for CP entries, but isn't right. > + printOperand(MI, Op); > + return; > + } > + > + O << "[" << getRegisterName(MO1.getReg()); > + if (MO3.getReg()) > + O << ", " << getRegisterName(MO3.getReg()); > + else if (unsigned ImmOffs = MO2.getImm()) > + O << ", #" << ImmOffs * Scale; > + O << "]"; > +} > + > +void ARMInstPrinter::printThumbAddrModeS1Operand(const MCInst *MI, unsigned Op) > +{ > + printThumbAddrModeRI5Operand(MI, Op, 1); > +} > + > +void ARMInstPrinter::printThumbAddrModeS2Operand(const MCInst *MI, unsigned Op) > +{ > + printThumbAddrModeRI5Operand(MI, Op, 2); > +} > + > +void ARMInstPrinter::printThumbAddrModeS4Operand(const MCInst *MI, unsigned Op) > +{ > + printThumbAddrModeRI5Operand(MI, Op, 4); > +} > + > +void ARMInstPrinter::printThumbAddrModeSPOperand(const MCInst *MI,unsigned Op) { > + const MCOperand &MO1 = MI->getOperand(Op); > + const MCOperand &MO2 = MI->getOperand(Op+1); > + O << "[" << getRegisterName(MO1.getReg()); > + if (unsigned ImmOffs = MO2.getImm()) > + O << ", #" << ImmOffs*4; > + O << "]"; > +} > + > +void ARMInstPrinter::printTBAddrMode(const MCInst *MI, unsigned OpNum) { > + O << "[pc, " << getRegisterName(MI->getOperand(OpNum).getReg()); > + if (MI->getOpcode() == ARM::t2TBH) > + O << ", lsl #1"; > + O << ']'; > +} > + > +// Constant shifts t2_so_reg is a 2-operand unit corresponding to the Thumb2 > +// register with shift forms. > +// REG 0 0 - e.g. R5 > +// REG IMM, SH_OPC - e.g. R5, LSL #3 > +void ARMInstPrinter::printT2SOOperand(const MCInst *MI, unsigned OpNum) { > + const MCOperand &MO1 = MI->getOperand(OpNum); > + const MCOperand &MO2 = MI->getOperand(OpNum+1); > + > + unsigned Reg = MO1.getReg(); > + O << getRegisterName(Reg); > + > + // Print the shift opc. > + O << ", " > + << ARM_AM::getShiftOpcStr(ARM_AM::getSORegShOp(MO2.getImm())) > + << " "; > + > + assert(MO2.isImm() && "Not a valid t2_so_reg value!"); > + O << "#" << ARM_AM::getSORegOffset(MO2.getImm()); > +} > + > +void ARMInstPrinter::printT2AddrModeImm12Operand(const MCInst *MI, > + unsigned OpNum) { > + const MCOperand &MO1 = MI->getOperand(OpNum); > + const MCOperand &MO2 = MI->getOperand(OpNum+1); > + > + O << "[" << getRegisterName(MO1.getReg()); > + > + unsigned OffImm = MO2.getImm(); > + if (OffImm) // Don't print +0. > + O << ", #" << OffImm; > + O << "]"; > +} > + > +void ARMInstPrinter::printT2AddrModeImm8Operand(const MCInst *MI, > + unsigned OpNum) { > + const MCOperand &MO1 = MI->getOperand(OpNum); > + const MCOperand &MO2 = MI->getOperand(OpNum+1); > + > + O << "[" << getRegisterName(MO1.getReg()); > + > + int32_t OffImm = (int32_t)MO2.getImm(); > + // Don't print +0. > + if (OffImm < 0) > + O << ", #-" << -OffImm; > + else if (OffImm > 0) > + O << ", #" << OffImm; > + O << "]"; > +} > + > +void ARMInstPrinter::printT2AddrModeImm8s4Operand(const MCInst *MI, > + unsigned OpNum) { > + const MCOperand &MO1 = MI->getOperand(OpNum); > + const MCOperand &MO2 = MI->getOperand(OpNum+1); > + > + O << "[" << getRegisterName(MO1.getReg()); > + > + int32_t OffImm = (int32_t)MO2.getImm() / 4; > + // Don't print +0. > + if (OffImm < 0) > + O << ", #-" << -OffImm * 4; > + else if (OffImm > 0) > + O << ", #" << OffImm * 4; > + O << "]"; > +} > + > +void ARMInstPrinter::printT2AddrModeImm8OffsetOperand(const MCInst *MI, > + unsigned OpNum) { > + const MCOperand &MO1 = MI->getOperand(OpNum); > + int32_t OffImm = (int32_t)MO1.getImm(); > + // Don't print +0. > + if (OffImm < 0) > + O << "#-" << -OffImm; > + else if (OffImm > 0) > + O << "#" << OffImm; > +} > + > +void ARMInstPrinter::printT2AddrModeImm8s4OffsetOperand(const MCInst *MI, > + unsigned OpNum) { > + const MCOperand &MO1 = MI->getOperand(OpNum); > + int32_t OffImm = (int32_t)MO1.getImm() / 4; > + // Don't print +0. > + if (OffImm < 0) > + O << "#-" << -OffImm * 4; > + else if (OffImm > 0) > + O << "#" << OffImm * 4; > +} > + > +void ARMInstPrinter::printT2AddrModeSoRegOperand(const MCInst *MI, > + unsigned OpNum) { > + const MCOperand &MO1 = MI->getOperand(OpNum); > + const MCOperand &MO2 = MI->getOperand(OpNum+1); > + const MCOperand &MO3 = MI->getOperand(OpNum+2); > + > + O << "[" << getRegisterName(MO1.getReg()); > + > + assert(MO2.getReg() && "Invalid so_reg load / store address!"); > + O << ", " << getRegisterName(MO2.getReg()); > + > + unsigned ShAmt = MO3.getImm(); > + if (ShAmt) { > + assert(ShAmt <= 3 && "Not a valid Thumb2 addressing mode!"); > + O << ", lsl #" << ShAmt; > + } > + O << "]"; > +} > + > +void ARMInstPrinter::printVFPf32ImmOperand(const MCInst *MI, unsigned OpNum) { > + O << '#' << MI->getOperand(OpNum).getImm(); > +} > + > +void ARMInstPrinter::printVFPf64ImmOperand(const MCInst *MI, unsigned OpNum) { > + O << '#' << MI->getOperand(OpNum).getImm(); > +} > + > > Modified: llvm/trunk/lib/Target/ARM/AsmPrinter/ARMInstPrinter.h > URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Target/ARM/AsmPrinter/ARMInstPrinter.h?rev=98637&r1=98636&r2=98637&view=diff > ============================================================================== > --- llvm/trunk/lib/Target/ARM/AsmPrinter/ARMInstPrinter.h (original) > +++ llvm/trunk/lib/Target/ARM/AsmPrinter/ARMInstPrinter.h Tue Mar 16 11:36:54 2010 > @@ -54,26 +54,26 @@ > void printBitfieldInvMaskImmOperand(const MCInst *MI, unsigned OpNum); > > void printThumbS4ImmOperand(const MCInst *MI, unsigned OpNum); > - void printThumbITMask(const MCInst *MI, unsigned OpNum) {} > - void printThumbAddrModeRROperand(const MCInst *MI, unsigned OpNum) {} > + void printThumbITMask(const MCInst *MI, unsigned OpNum); > + void printThumbAddrModeRROperand(const MCInst *MI, unsigned OpNum); > void printThumbAddrModeRI5Operand(const MCInst *MI, unsigned OpNum, > - unsigned Scale) {} > - void printThumbAddrModeS1Operand(const MCInst *MI, unsigned OpNum) {} > - void printThumbAddrModeS2Operand(const MCInst *MI, unsigned OpNum) {} > - void printThumbAddrModeS4Operand(const MCInst *MI, unsigned OpNum) {} > - void printThumbAddrModeSPOperand(const MCInst *MI, unsigned OpNum) {} > + unsigned Scale); > + void printThumbAddrModeS1Operand(const MCInst *MI, unsigned OpNum); > + void printThumbAddrModeS2Operand(const MCInst *MI, unsigned OpNum); > + void printThumbAddrModeS4Operand(const MCInst *MI, unsigned OpNum); > + void printThumbAddrModeSPOperand(const MCInst *MI, unsigned OpNum); > > - void printT2SOOperand(const MCInst *MI, unsigned OpNum) {} > - void printT2AddrModeImm12Operand(const MCInst *MI, unsigned OpNum) {} > - void printT2AddrModeImm8Operand(const MCInst *MI, unsigned OpNum) {} > - void printT2AddrModeImm8s4Operand(const MCInst *MI, unsigned OpNum) {} > - void printT2AddrModeImm8OffsetOperand(const MCInst *MI, unsigned OpNum) {} > - void printT2AddrModeImm8s4OffsetOperand(const MCInst *MI, unsigned OpNum) {} > - void printT2AddrModeSoRegOperand(const MCInst *MI, unsigned OpNum) {} > + void printT2SOOperand(const MCInst *MI, unsigned OpNum); > + void printT2AddrModeImm12Operand(const MCInst *MI, unsigned OpNum); > + void printT2AddrModeImm8Operand(const MCInst *MI, unsigned OpNum); > + void printT2AddrModeImm8s4Operand(const MCInst *MI, unsigned OpNum); > + void printT2AddrModeImm8OffsetOperand(const MCInst *MI, unsigned OpNum); > + void printT2AddrModeImm8s4OffsetOperand(const MCInst *MI, unsigned OpNum); > + void printT2AddrModeSoRegOperand(const MCInst *MI, unsigned OpNum); > > - void printCPSOptionOperand(const MCInst *MI, unsigned OpNum) {} > - void printMSRMaskOperand(const MCInst *MI, unsigned OpNum) {} > - void printNegZeroOperand(const MCInst *MI, unsigned OpNum) {} > + void printCPSOptionOperand(const MCInst *MI, unsigned OpNum); > + void printMSRMaskOperand(const MCInst *MI, unsigned OpNum); > + void printNegZeroOperand(const MCInst *MI, unsigned OpNum); > void printPredicateOperand(const MCInst *MI, unsigned OpNum); > void printMandatoryPredicateOperand(const MCInst *MI, unsigned OpNum); > void printSBitModifierOperand(const MCInst *MI, unsigned OpNum); > @@ -82,10 +82,10 @@ > const char *Modifier); > void printJTBlockOperand(const MCInst *MI, unsigned OpNum) {} > void printJT2BlockOperand(const MCInst *MI, unsigned OpNum) {} > - void printTBAddrMode(const MCInst *MI, unsigned OpNum) {} > + void printTBAddrMode(const MCInst *MI, unsigned OpNum); > void printNoHashImmediate(const MCInst *MI, unsigned OpNum); > - void printVFPf32ImmOperand(const MCInst *MI, int OpNum) {} > - void printVFPf64ImmOperand(const MCInst *MI, int OpNum) {} > + void printVFPf32ImmOperand(const MCInst *MI, unsigned OpNum); > + void printVFPf64ImmOperand(const MCInst *MI, unsigned OpNum); > void printHex8ImmOperand(const MCInst *MI, int OpNum) {} > void printHex16ImmOperand(const MCInst *MI, int OpNum) {} > void printHex32ImmOperand(const MCInst *MI, int OpNum) {} > > Added: llvm/trunk/lib/Target/ARM/Disassembler/ARMDisassembler.cpp > URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Target/ARM/Disassembler/ARMDisassembler.cpp?rev=98637&view=auto > ============================================================================== > --- llvm/trunk/lib/Target/ARM/Disassembler/ARMDisassembler.cpp (added) > +++ llvm/trunk/lib/Target/ARM/Disassembler/ARMDisassembler.cpp Tue Mar 16 11:36:54 2010 > @@ -0,0 +1,513 @@ > +//===- ARMDisassembler.cpp - Disassembler for ARM/Thumb ISA ----*- C++ -*-===// > +// > +// The LLVM Compiler Infrastructure > +// > +// This file is distributed under the University of Illinois Open Source > +// License. See LICENSE.TXT for details. > +// > +//===----------------------------------------------------------------------===// > +// > +// This file is part of the ARM Disassembler. > +// It contains code to translate the data produced by the decoder into MCInsts. > +// Documentation for the disassembler can be found in ARMDisassembler.h. > +// > +//===----------------------------------------------------------------------===// > + > +#define DEBUG_TYPE "arm-disassembler" > + > +#include "ARMDisassembler.h" > +#include "ARMDisassemblerCore.h" > + > +#include "llvm/MC/MCInst.h" > +#include "llvm/Target/TargetRegistry.h" > +#include "llvm/Support/Debug.h" > +#include "llvm/Support/MemoryObject.h" > +#include "llvm/Support/ErrorHandling.h" > +#include "llvm/Support/raw_ostream.h" > + > +/// ARMDisassemblerTables.inc - ARMDisassemblerTables.inc is tblgen'ed from > +/// RISCDisassemblerEmitter.cpp TableGen backend. It contains: > +/// > +/// o Mappings from opcode to ARM/Thumb instruction format > +/// > +/// o static uint16_t decodeInstruction(uint32_t insn) - the decoding function > +/// for an ARM instruction. > +/// > +/// o static uint16_t decodeThumbInstruction(field_t insn) - the decoding > +/// function for a Thumb instruction. > +/// > +#include "../ARMGenDisassemblerTables.inc" > + > +namespace llvm { > + > +namespace ARMDisassembler { > + > +/// showBitVector - Use the raw_ostream to log a diagnostic message describing > +/// the inidividual bits of the instruction. This is a sample output: > +/// > +/// 31 30 29 28 27 26 25 24 23 22 21 20 19 18 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0 > +/// ------------------------------------------------------------------------------------------------- > +/// | 1: 0: 1: 0| 1: 0: 1: 0| 1: 0: 1: 0| 1: 0: 1: 0| 1: 0: 1: 0| 1: 0: 1: 0| 1: 0: 1: 0| 1: 0: 1: 0| > +/// ------------------------------------------------------------------------------------------------- > +/// > +static inline void showBitVector(raw_ostream &os, const uint32_t &insn) { > + os << " 31 30 29 28 27 26 25 24 23 22 21 20 19 18 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0 \n"; > + os << "-------------------------------------------------------------------------------------------------\n"; > + os << '|'; > + for (unsigned i = 32; i != 0; --i) { > + if (insn >> (i - 1) & 0x01) > + os << " 1"; > + else > + os << " 0"; > + os << (i%4 == 1 ? '|' : ':'); > + } > + os << '\n'; > + os << "-------------------------------------------------------------------------------------------------\n"; > + os << '\n'; > +} > + > +/// decodeARMInstruction is a decorator function which tries special cases of > +/// instruction matching before calling the auto-generated decoder function. > +static unsigned decodeARMInstruction(uint32_t &insn) { > + if (slice(insn, 31, 28) == 15) > + goto AutoGenedDecoder; > + > + // Special case processing, if any, goes here.... > + > + // LLVM combines the offset mode of A8.6.197 & A8.6.198 into STRB. > + // The insufficient encoding information of the combined instruction confuses > + // the decoder wrt BFC/BFI. Therefore, we try to recover here. > + // For BFC, Inst{27-21} = 0b0111110 & Inst{6-0} = 0b0011111. > + // For BFI, Inst{27-21} = 0b0111110 & Inst{6-4} = 0b001 & Inst{3-0} =! 0b1111. > + if (slice(insn, 27, 21) == 0x3e && slice(insn, 6, 4) == 1) { > + if (slice(insn, 3, 0) == 15) > + return ARM::BFC; > + else > + return ARM::BFI; > + } > + > + // Ditto for ADDSrs, which is a super-instruction for A8.6.7 & A8.6.8. > + // As a result, the decoder fails to decode UMULL properly. > + if (slice(insn, 27, 21) == 0x04 && slice(insn, 7, 4) == 9) { > + return ARM::UMULL; > + } > + > + // Ditto for STR_PRE, which is a super-instruction for A8.6.194 & A8.6.195. > + // As a result, the decoder fails to decode SBFX properly. > + if (slice(insn, 27, 21) == 0x3d && slice(insn, 6, 4) == 5) > + return ARM::SBFX; > + > + // And STRB_PRE, which is a super-instruction for A8.6.197 & A8.6.198. > + // As a result, the decoder fails to decode UBFX properly. > + if (slice(insn, 27, 21) == 0x3f && slice(insn, 6, 4) == 5) > + return ARM::UBFX; > + > + // Ditto for STRT, which is a super-instruction for A8.6.210 Encoding A1 & A2. > + // As a result, the decoder fails to deocode SSAT properly. > + if (slice(insn, 27, 21) == 0x35 && slice(insn, 5, 4) == 1) > + return slice(insn, 6, 6) == 0 ? ARM::SSATlsl : ARM::SSATasr; > + > + // Ditto for RSCrs, which is a super-instruction for A8.6.146 & A8.6.147. > + // As a result, the decoder fails to decode STRHT/LDRHT/LDRSHT/LDRSBT. > + if (slice(insn, 27, 24) == 0) { > + switch (slice(insn, 21, 20)) { > + case 2: > + switch (slice(insn, 7, 4)) { > + case 11: > + return ARM::STRHT; > + default: > + break; // fallthrough > + } > + break; > + case 3: > + switch (slice(insn, 7, 4)) { > + case 11: > + return ARM::LDRHT; > + case 13: > + return ARM::LDRSBT; > + case 15: > + return ARM::LDRSHT; > + default: > + break; // fallthrough > + } > + break; > + default: > + break; // fallthrough > + } > + } > + > + // Ditto for SBCrs, which is a super-instruction for A8.6.152 & A8.6.153. > + // As a result, the decoder fails to decode STRH_Post/LDRD_POST/STRD_POST > + // properly. > + if (slice(insn, 27, 25) == 0 && slice(insn, 20, 20) == 0) { > + unsigned PW = slice(insn, 24, 24) << 1 | slice(insn, 21, 21); > + switch (slice(insn, 7, 4)) { > + case 11: > + switch (PW) { > + case 2: // Offset > + return ARM::STRH; > + case 3: // Pre-indexed > + return ARM::STRH_PRE; > + case 0: // Post-indexed > + return ARM::STRH_POST; > + default: > + break; // fallthrough > + } > + break; > + case 13: > + switch (PW) { > + case 2: // Offset > + return ARM::LDRD; > + case 3: // Pre-indexed > + return ARM::LDRD_PRE; > + case 0: // Post-indexed > + return ARM::LDRD_POST; > + default: > + break; // fallthrough > + } > + break; > + case 15: > + switch (PW) { > + case 2: // Offset > + return ARM::STRD; > + case 3: // Pre-indexed > + return ARM::STRD_PRE; > + case 0: // Post-indexed > + return ARM::STRD_POST; > + default: > + break; // fallthrough > + } > + break; > + default: > + break; // fallthrough > + } > + } > + > + // Ditto for SBCSSrs, which is a super-instruction for A8.6.152 & A8.6.153. > + // As a result, the decoder fails to decode LDRH_POST/LDRSB_POST/LDRSH_POST > + // properly. > + if (slice(insn, 27, 25) == 0 && slice(insn, 20, 20) == 1) { > + unsigned PW = slice(insn, 24, 24) << 1 | slice(insn, 21, 21); > + switch (slice(insn, 7, 4)) { > + case 11: > + switch (PW) { > + case 2: // Offset > + return ARM::LDRH; > + case 3: // Pre-indexed > + return ARM::LDRH_PRE; > + case 0: // Post-indexed > + return ARM::LDRH_POST; > + default: > + break; // fallthrough > + } > + break; > + case 13: > + switch (PW) { > + case 2: // Offset > + return ARM::LDRSB; > + case 3: // Pre-indexed > + return ARM::LDRSB_PRE; > + case 0: // Post-indexed > + return ARM::LDRSB_POST; > + default: > + break; // fallthrough > + } > + break; > + case 15: > + switch (PW) { > + case 2: // Offset > + return ARM::LDRSH; > + case 3: // Pre-indexed > + return ARM::LDRSH_PRE; > + case 0: // Post-indexed > + return ARM::LDRSH_POST; > + default: > + break; // fallthrough > + } > + break; > + default: > + break; // fallthrough > + } > + } > + > +AutoGenedDecoder: > + // Calling the auto-generated decoder function. > + return decodeInstruction(insn); > +} > + > +// Helper function for special case handling of LDR (literal) and friends. > +// See, for example, A6.3.7 Load word: Table A6-18 Load word. > +// See A8.6.57 T3, T4 & A8.6.60 T2 and friends for why we morphed the opcode > +// before passing it on. > +static unsigned T2Morph2LoadLiteral(unsigned Opcode) { > + switch (Opcode) { > + default: > + return Opcode; // Return unmorphed opcode. > + > + case ARM::t2LDRDi8: > + return ARM::t2LDRDpci; > + > + case ARM::t2LDR_POST: case ARM::t2LDR_PRE: > + case ARM::t2LDRi12: case ARM::t2LDRi8: > + case ARM::t2LDRs: > + return ARM::t2LDRpci; > + > + case ARM::t2LDRB_POST: case ARM::t2LDRB_PRE: > + case ARM::t2LDRBi12: case ARM::t2LDRBi8: > + case ARM::t2LDRBs: > + return ARM::t2LDRBpci; > + > + case ARM::t2LDRH_POST: case ARM::t2LDRH_PRE: > + case ARM::t2LDRHi12: case ARM::t2LDRHi8: > + case ARM::t2LDRHs: > + return ARM::t2LDRHpci; > + > + case ARM::t2LDRSB_POST: case ARM::t2LDRSB_PRE: > + case ARM::t2LDRSBi12: case ARM::t2LDRSBi8: > + case ARM::t2LDRSBs: > + return ARM::t2LDRSBpci; > + > + case ARM::t2LDRSH_POST: case ARM::t2LDRSH_PRE: > + case ARM::t2LDRSHi12: case ARM::t2LDRSHi8: > + case ARM::t2LDRSHs: > + return ARM::t2LDRSHpci; > + } > +} > + > +/// decodeThumbSideEffect is a decorator function which can potentially twiddle > +/// the instruction or morph the returned opcode under Thumb2. > +/// > +/// First it checks whether the insn is a NEON or VFP instr; if true, bit > +/// twiddling could be performed on insn to turn it into an ARM NEON/VFP > +/// equivalent instruction and decodeInstruction is called with the transformed > +/// insn. > +/// > +/// Next, there is special handling for Load byte/halfword/word instruction by > +/// checking whether Rn=0b1111 and call T2Morph2LoadLiteral() on the decoded > +/// Thumb2 instruction. See comments below for further details. > +/// > +/// Finally, one last check is made to see whether the insn is a NEON/VFP and > +/// decodeInstruction(insn) is invoked on the original insn. > +/// > +/// Otherwise, decodeThumbInstruction is called with the original insn. > +static unsigned decodeThumbSideEffect(bool IsThumb2, uint32_t &insn) { > + if (IsThumb2) { > + uint16_t op1 = slice(insn, 28, 27); > + uint16_t op2 = slice(insn, 26, 20); > + > + // A6.3 32-bit Thumb instruction encoding > + // Table A6-9 32-bit Thumb instruction encoding > + > + // The coprocessor instructions of interest are transformed to their ARM > + // equivalents. > + > + // --------- Transform Begin Marker --------- > + if ((op1 == 1 || op1 == 3) && slice(op2, 6, 4) == 7) { > + // A7.4 Advanced SIMD data-processing instructions > + // U bit of Thumb corresponds to Inst{24} of ARM. > + uint16_t U = slice(op1, 1, 1); > + > + // Inst{28-24} of ARM = {1,0,0,1,U}; > + uint16_t bits28_24 = 9 << 1 | U; > + DEBUG(showBitVector(errs(), insn)); > + setSlice(insn, 28, 24, bits28_24); > + return decodeInstruction(insn); > + } > + > + if (op1 == 3 && slice(op2, 6, 4) == 1 && slice(op2, 0, 0) == 0) { > + // A7.7 Advanced SIMD element or structure load/store instructions > + // Inst{27-24} of Thumb = 0b1001 > + // Inst{27-24} of ARM = 0b0100 > + DEBUG(showBitVector(errs(), insn)); > + setSlice(insn, 27, 24, 4); > + return decodeInstruction(insn); > + } > + // --------- Transform End Marker --------- > + > + // See, for example, A6.3.7 Load word: Table A6-18 Load word. > + // See A8.6.57 T3, T4 & A8.6.60 T2 and friends for why we morphed the opcode > + // before passing it on to our delegate. > + if (op1 == 3 && slice(op2, 6, 5) == 0 && slice(op2, 0, 0) == 1 > + && slice(insn, 19, 16) == 15) > + return T2Morph2LoadLiteral(decodeThumbInstruction(insn)); > + > + // One last check for NEON/VFP instructions. > + if ((op1 == 1 || op1 == 3) && slice(op2, 6, 6) == 1) > + return decodeInstruction(insn); > + > + // Fall through. > + } > + > + return decodeThumbInstruction(insn); > +} > + > +static inline bool Thumb2PreloadOpcodeNoPCI(unsigned Opcode) { > + switch (Opcode) { > + default: > + return false; > + case ARM::t2PLDi12: case ARM::t2PLDi8: > + case ARM::t2PLDr: case ARM::t2PLDs: > + case ARM::t2PLDWi12: case ARM::t2PLDWi8: > + case ARM::t2PLDWr: case ARM::t2PLDWs: > + case ARM::t2PLIi12: case ARM::t2PLIi8: > + case ARM::t2PLIr: case ARM::t2PLIs: > + return true; > + } > +} > + > +static inline unsigned T2Morph2Preload2PCI(unsigned Opcode) { > + switch (Opcode) { > + default: > + return 0; > + case ARM::t2PLDi12: case ARM::t2PLDi8: > + case ARM::t2PLDr: case ARM::t2PLDs: > + return ARM::t2PLDpci; > + case ARM::t2PLDWi12: case ARM::t2PLDWi8: > + case ARM::t2PLDWr: case ARM::t2PLDWs: > + return ARM::t2PLDWpci; > + case ARM::t2PLIi12: case ARM::t2PLIi8: > + case ARM::t2PLIr: case ARM::t2PLIs: > + return ARM::t2PLIpci; > + } > +} > + > +// > +// Public interface for the disassembler > +// > + > +bool ARMDisassembler::getInstruction(MCInst &MI, > + uint64_t &Size, > + const MemoryObject &Region, > + uint64_t Address, > + raw_ostream &os) const { > + // The machine instruction. > + uint32_t insn; > + > + // We want to read exactly 4 bytes of data. > + if (Region.readBytes(Address, 4, (uint8_t*)&insn, NULL) == -1) > + return false; > + > + unsigned Opcode = decodeARMInstruction(insn); > + ARMFormat Format = ARMFormats[Opcode]; > + NSFormat NSF = NSFormats[Opcode]; > + Size = 4; > + > + DEBUG({ > + errs() << "Opcode=" << Opcode << " Name=" << ARMUtils::OpcodeName(Opcode) > + << " Format=" << stringForARMFormat(Format) << " NSFormat=" > + << stringForNSFormat(NSF) << '\n'; > + showBitVector(errs(), insn); > + }); > + > + AbstractARMMCBuilder *Builder = > + ARMMCBuilderFactory::CreateMCBuilder(Opcode, Format, NSF); > + > + if (!Builder) > + return false; > + > + if (!Builder->Build(MI, insn)) > + return false; > + > + delete Builder; > + > + return true; > +} > + > +bool ThumbDisassembler::getInstruction(MCInst &MI, > + uint64_t &Size, > + const MemoryObject &Region, > + uint64_t Address, > + raw_ostream &os) const { > + // The machine instruction. > + uint32_t insn = 0; > + uint32_t insn1 = 0; > + > + // A6.1 Thumb instruction set encoding > + // > + // If bits [15:11] of the halfword being decoded take any of the following > + // values, the halfword is the first halfword of a 32-bit instruction: > + // o 0b11101 > + // o 0b11110 > + // o 0b11111. > + // > + // Otherwise, the halfword is a 16-bit instruction. > + > + // Read 2 bytes of data first. > + if (Region.readBytes(Address, 2, (uint8_t*)&insn, NULL) == -1) > + return false; > + > + unsigned bits15_11 = slice(insn, 15, 11); > + bool IsThumb2 = false; > + > + // 32-bit instructions if the bits [15:11] of the halfword matches > + // { 0b11101 /* 0x1D */, 0b11110 /* 0x1E */, ob11111 /* 0x1F */ }. > + if (bits15_11 == 0x1D || bits15_11 == 0x1E || bits15_11 == 0x1F) { > + IsThumb2 = true; > + if (Region.readBytes(Address + 2, 2, (uint8_t*)&insn1, NULL) == -1) > + return false; > + insn = (insn << 16 | insn1); > + } > + > + // The insn could potentially be bit-twiddled in order to be decoded as an ARM > + // NEON/VFP opcode. In such case, the modified insn is later disassembled as > + // an ARM NEON/VFP instruction. > + // > + // This is a short term solution for lack of encoding bits specified for the > + // Thumb2 NEON/VFP instructions. The long term solution could be adding some > + // infrastructure to have each instruction support more than one encodings. > + // Which encoding is used would be based on which subtarget the compiler/ > + // disassembler is working with at the time. This would allow the sharing of > + // the NEON patterns between ARM and Thumb2, as well as potential greater > + // sharing between the regular ARM instructions and the 32-bit wide Thumb2 > + // instructions as well. > + unsigned Opcode = decodeThumbSideEffect(IsThumb2, insn); > + > + // A8.6.117/119/120/121. > + // PLD/PLDW/PLI instructions with Rn==15 is transformed to the pci variant. > + if (Thumb2PreloadOpcodeNoPCI(Opcode) && slice(insn, 19, 16) == 15) > + Opcode = T2Morph2Preload2PCI(Opcode); > + > + ARMFormat Format = ARMFormats[Opcode]; > + NSFormat NSF = NSFormats[Opcode]; > + Size = IsThumb2 ? 4 : 2; > + > + DEBUG({ > + errs() << "Opcode=" << Opcode << " Name=" << ARMUtils::OpcodeName(Opcode) > + << " Format=" << stringForARMFormat(Format) << " NSFormat=" > + << stringForNSFormat(NSF) << '\n'; > + showBitVector(errs(), insn); > + }); > + > + AbstractARMMCBuilder *Builder = > + ARMMCBuilderFactory::CreateMCBuilder(Opcode, Format, NSF); > + > + if (!Builder) > + return false; > + > + if (!Builder->Build(MI, insn)) > + return false; > + > + delete Builder; > + > + return true; > +} > + > +} // namespace ARM Disassembler > + > +static const MCDisassembler *createARMDisassembler(const Target &T) { > + return new ARMDisassembler::ARMDisassembler; > +} > + > +static const MCDisassembler *createThumbDisassembler(const Target &T) { > + return new ARMDisassembler::ThumbDisassembler; > +} > + > +extern "C" void LLVMInitializeARMDisassembler() { > + // Register the disassembler. > + TargetRegistry::RegisterMCDisassembler(TheARMTarget, > + createARMDisassembler); > + TargetRegistry::RegisterMCDisassembler(TheThumbTarget, > + createThumbDisassembler); > +} > + > +} // namespace llvm > > Added: llvm/trunk/lib/Target/ARM/Disassembler/ARMDisassembler.h > URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Target/ARM/Disassembler/ARMDisassembler.h?rev=98637&view=auto > ============================================================================== > --- llvm/trunk/lib/Target/ARM/Disassembler/ARMDisassembler.h (added) > +++ llvm/trunk/lib/Target/ARM/Disassembler/ARMDisassembler.h Tue Mar 16 11:36:54 2010 > @@ -0,0 +1,71 @@ > +//===- X86Disassembler.h - Disassembler for x86 and x86_64 ------*- C++ -*-===// > +// > +// The LLVM Compiler Infrastructure > +// > +// This file is distributed under the University of Illinois Open Source > +// License. See LICENSE.TXT for details. > +// > +//===----------------------------------------------------------------------===// > +// > +//===----------------------------------------------------------------------===// > + > +#ifndef ARMDISASSEMBLER_H > +#define ARMDISASSEMBLER_H > + > +#include "llvm/MC/MCDisassembler.h" > + > +namespace llvm { > + > +class MCInst; > +class MemoryObject; > +class raw_ostream; > + > +namespace ARMDisassembler { > + > +/// ARMDisassembler - ARM disassembler for all ARM platforms. > +class ARMDisassembler : public MCDisassembler { > +public: > + /// Constructor - Initializes the disassembler. > + /// > + ARMDisassembler() : > + MCDisassembler() { > + } > + > + ~ARMDisassembler() { > + } > + > + /// getInstruction - See MCDisassembler. > + bool getInstruction(MCInst &instr, > + uint64_t &size, > + const MemoryObject ®ion, > + uint64_t address, > + raw_ostream &vStream) const; > +private: > +}; > + > +/// ThumbDisassembler - Thumb disassembler for all ARM platforms. > +class ThumbDisassembler : public MCDisassembler { > +public: > + /// Constructor - Initializes the disassembler. > + /// > + ThumbDisassembler() : > + MCDisassembler() { > + } > + > + ~ThumbDisassembler() { > + } > + > + /// getInstruction - See MCDisassembler. > + bool getInstruction(MCInst &instr, > + uint64_t &size, > + const MemoryObject ®ion, > + uint64_t address, > + raw_ostream &vStream) const; > +private: > +}; > + > +} // namespace ARMDisassembler > + > +} // namespace llvm > + > +#endif > > Added: llvm/trunk/lib/Target/ARM/Disassembler/ARMDisassemblerCore.cpp > URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Target/ARM/Disassembler/ARMDisassemblerCore.cpp?rev=98637&view=auto > ============================================================================== > --- llvm/trunk/lib/Target/ARM/Disassembler/ARMDisassemblerCore.cpp (added) > +++ llvm/trunk/lib/Target/ARM/Disassembler/ARMDisassemblerCore.cpp Tue Mar 16 11:36:54 2010 > @@ -0,0 +1,3351 @@ > +//===- ARMDisassemblerCore.cpp - ARM disassembler helpers ----*- C++ -*-===// > +// > +// The LLVM Compiler Infrastructure > +// > +// This file is distributed under the University of Illinois Open Source > +// License. See LICENSE.TXT for details. > +// > +//===----------------------------------------------------------------------===// > +// > +// This file is part of the ARM Disassembler. > +// It contains code to represent the core concepts of Builder, Builder Factory, > +// as well as the Algorithm to solve the problem of disassembling an ARM instr. > +// > +//===----------------------------------------------------------------------===// > + > +#include "ARMAddressingModes.h" > +#include "ARMDisassemblerCore.h" > +#include > + > +/// ARMGenInstrInfo.inc - ARMGenInstrInfo.inc contains the static const > +/// TargetInstrDesc ARMInsts[] definition and the TargetOperandInfo[]'s > +/// describing the operand info for each ARMInsts[i]. > +/// > +/// Together with an instruction's encoding format, we can take advantage of the > +/// NumOperands and the OpInfo fields of the target instruction description in > +/// the quest to build out the MCOperand list for an MCInst. > +/// > +/// The general guideline is that with a known format, the number of dst and src > +/// operands are well-known. The dst is built first, followed by the src > +/// operand(s). The operands not yet used at this point are for the Implicit > +/// Uses and Defs by this instr. For the Uses part, the pred:$p operand is > +/// defined with two components: > +/// > +/// def pred { // Operand PredicateOperand > +/// ValueType Type = OtherVT; > +/// string PrintMethod = "printPredicateOperand"; > +/// string AsmOperandLowerMethod = ?; > +/// dag MIOperandInfo = (ops i32imm, CCR); > +/// AsmOperandClass ParserMatchClass = ImmAsmOperand; > +/// dag DefaultOps = (ops (i32 14), (i32 zero_reg)); > +/// } > +/// > +/// which is manifested by the TargetOperandInfo[] of: > +/// > +/// { 0, 0|(1< +/// { ARM::CCRRegClassID, 0|(1< +/// > +/// So the first predicate MCOperand corresponds to the immediate part of the > +/// ARM condition field (Inst{31-28}), and the second predicate MCOperand > +/// corresponds to a register kind of ARM::CPSR. > +/// > +/// For the Defs part, in the simple case of only cc_out:$s, we have: > +/// > +/// def cc_out { // Operand OptionalDefOperand > +/// ValueType Type = OtherVT; > +/// string PrintMethod = "printSBitModifierOperand"; > +/// string AsmOperandLowerMethod = ?; > +/// dag MIOperandInfo = (ops CCR); > +/// AsmOperandClass ParserMatchClass = ImmAsmOperand; > +/// dag DefaultOps = (ops (i32 zero_reg)); > +/// } > +/// > +/// which is manifested by the one TargetOperandInfo of: > +/// > +/// { ARM::CCRRegClassID, 0|(1< +/// > +/// And this maps to one MCOperand with the regsiter kind of ARM::CPSR. > +#include "ARMGenInstrInfo.inc" > + > +using namespace llvm; > + > +const char *ARMUtils::OpcodeName(unsigned Opcode) { > + return ARMInsts[Opcode].Name; > +} > + > +// There is a more efficient way than the following. It is fragile, though. > +// See the code snippet after this function. > +static unsigned getRegisterEnum(unsigned RegClassID, unsigned RawRegister, > + bool DRegPair = false) { > + > + if (DRegPair && RegClassID == ARM::QPRRegClassID) { > + // LLVM expects { Dd, Dd+1 } to form a super register; this is not specified > + // in the ARM Architecture Manual as far as I understand it (A8.6.307). > + // Therefore, we morph the RegClassID to be the sub register class and don't > + // subsequently transform the RawRegister encoding when calculating RegNum. > + // > + // See also ARMinstPrinter::printOperand() wrt "dregpair" modifier part > + // where this workaround is meant for. > + RegClassID = ARM::DPRRegClassID; > + } > + > + // See also decodeNEONRd(), decodeNEONRn(), decodeNEONRm(). > + unsigned RegNum = > + RegClassID == ARM::QPRRegClassID ? RawRegister >> 1 : RawRegister; > + > + switch (RegNum) { > + default: > + break; > + case 0: > + switch (RegClassID) { > + case ARM::GPRRegClassID: case ARM::tGPRRegClassID: return ARM::R0; > + case ARM::DPRRegClassID: case ARM::DPR_8RegClassID: > + case ARM::DPR_VFP2RegClassID: > + return ARM::D0; > + case ARM::QPRRegClassID: case ARM::QPR_8RegClassID: > + case ARM::QPR_VFP2RegClassID: > + return ARM::Q0; > + case ARM::SPRRegClassID: case ARM::SPR_8RegClassID: return ARM::S0; > + } > + break; > + case 1: > + switch (RegClassID) { > + case ARM::GPRRegClassID: case ARM::tGPRRegClassID: return ARM::R1; > + case ARM::DPRRegClassID: case ARM::DPR_8RegClassID: > + case ARM::DPR_VFP2RegClassID: > + return ARM::D1; > + case ARM::QPRRegClassID: case ARM::QPR_8RegClassID: > + case ARM::QPR_VFP2RegClassID: > + return ARM::Q1; > + case ARM::SPRRegClassID: case ARM::SPR_8RegClassID: return ARM::S1; > + } > + break; > + case 2: > + switch (RegClassID) { > + case ARM::GPRRegClassID: case ARM::tGPRRegClassID: return ARM::R2; > + case ARM::DPRRegClassID: case ARM::DPR_8RegClassID: > + case ARM::DPR_VFP2RegClassID: > + return ARM::D2; > + case ARM::QPRRegClassID: case ARM::QPR_8RegClassID: > + case ARM::QPR_VFP2RegClassID: > + return ARM::Q2; > + case ARM::SPRRegClassID: case ARM::SPR_8RegClassID: return ARM::S2; > + } > + break; > + case 3: > + switch (RegClassID) { > + case ARM::GPRRegClassID: case ARM::tGPRRegClassID: return ARM::R3; > + case ARM::DPRRegClassID: case ARM::DPR_8RegClassID: > + case ARM::DPR_VFP2RegClassID: > + return ARM::D3; > + case ARM::QPRRegClassID: case ARM::QPR_8RegClassID: > + case ARM::QPR_VFP2RegClassID: > + return ARM::Q3; > + case ARM::SPRRegClassID: case ARM::SPR_8RegClassID: return ARM::S3; > + } > + break; > + case 4: > + switch (RegClassID) { > + case ARM::GPRRegClassID: case ARM::tGPRRegClassID: return ARM::R4; > + case ARM::DPRRegClassID: case ARM::DPR_8RegClassID: > + case ARM::DPR_VFP2RegClassID: > + return ARM::D4; > + case ARM::QPRRegClassID: case ARM::QPR_VFP2RegClassID: return ARM::Q4; > + case ARM::SPRRegClassID: case ARM::SPR_8RegClassID: return ARM::S4; > + } > + break; > + case 5: > + switch (RegClassID) { > + case ARM::GPRRegClassID: case ARM::tGPRRegClassID: return ARM::R5; > + case ARM::DPRRegClassID: case ARM::DPR_8RegClassID: > + case ARM::DPR_VFP2RegClassID: > + return ARM::D5; > + case ARM::QPRRegClassID: case ARM::QPR_VFP2RegClassID: return ARM::Q5; > + case ARM::SPRRegClassID: case ARM::SPR_8RegClassID: return ARM::S5; > + } > + break; > + case 6: > + switch (RegClassID) { > + case ARM::GPRRegClassID: case ARM::tGPRRegClassID: return ARM::R6; > + case ARM::DPRRegClassID: case ARM::DPR_8RegClassID: > + case ARM::DPR_VFP2RegClassID: > + return ARM::D6; > + case ARM::QPRRegClassID: case ARM::QPR_VFP2RegClassID: return ARM::Q6; > + case ARM::SPRRegClassID: case ARM::SPR_8RegClassID: return ARM::S6; > + } > + break; > + case 7: > + switch (RegClassID) { > + case ARM::GPRRegClassID: case ARM::tGPRRegClassID: return ARM::R7; > + case ARM::DPRRegClassID: case ARM::DPR_8RegClassID: > + case ARM::DPR_VFP2RegClassID: > + return ARM::D7; > + case ARM::QPRRegClassID: case ARM::QPR_VFP2RegClassID: return ARM::Q7; > + case ARM::SPRRegClassID: case ARM::SPR_8RegClassID: return ARM::S7; > + } > + break; > + case 8: > + switch (RegClassID) { > + case ARM::GPRRegClassID: return ARM::R8; > + case ARM::DPRRegClassID: case ARM::DPR_VFP2RegClassID: return ARM::D8; > + case ARM::QPRRegClassID: return ARM::Q8; > + case ARM::SPRRegClassID: case ARM::SPR_8RegClassID: return ARM::S8; > + } > + break; > + case 9: > + switch (RegClassID) { > + case ARM::GPRRegClassID: return ARM::R9; > + case ARM::DPRRegClassID: case ARM::DPR_VFP2RegClassID: return ARM::D9; > + case ARM::QPRRegClassID: return ARM::Q9; > + case ARM::SPRRegClassID: case ARM::SPR_8RegClassID: return ARM::S9; > + } > + break; > + case 10: > + switch (RegClassID) { > + case ARM::GPRRegClassID: return ARM::R10; > + case ARM::DPRRegClassID: case ARM::DPR_VFP2RegClassID: return ARM::D10; > + case ARM::QPRRegClassID: return ARM::Q10; > + case ARM::SPRRegClassID: case ARM::SPR_8RegClassID: return ARM::S10; > + } > + break; > + case 11: > + switch (RegClassID) { > + case ARM::GPRRegClassID: return ARM::R11; > + case ARM::DPRRegClassID: case ARM::DPR_VFP2RegClassID: return ARM::D11; > + case ARM::QPRRegClassID: return ARM::Q11; > + case ARM::SPRRegClassID: case ARM::SPR_8RegClassID: return ARM::S11; > + } > + break; > + case 12: > + switch (RegClassID) { > + case ARM::GPRRegClassID: return ARM::R12; > + case ARM::DPRRegClassID: case ARM::DPR_VFP2RegClassID: return ARM::D12; > + case ARM::QPRRegClassID: return ARM::Q12; > + case ARM::SPRRegClassID: case ARM::SPR_8RegClassID: return ARM::S12; > + } > + break; > + case 13: > + switch (RegClassID) { > + case ARM::GPRRegClassID: return ARM::SP; > + case ARM::DPRRegClassID: case ARM::DPR_VFP2RegClassID: return ARM::D13; > + case ARM::QPRRegClassID: return ARM::Q13; > + case ARM::SPRRegClassID: case ARM::SPR_8RegClassID: return ARM::S13; > + } > + break; > + case 14: > + switch (RegClassID) { > + case ARM::GPRRegClassID: return ARM::LR; > + case ARM::DPRRegClassID: case ARM::DPR_VFP2RegClassID: return ARM::D14; > + case ARM::QPRRegClassID: return ARM::Q14; > + case ARM::SPRRegClassID: case ARM::SPR_8RegClassID: return ARM::S14; > + } > + break; > + case 15: > + switch (RegClassID) { > + case ARM::GPRRegClassID: return ARM::PC; > + case ARM::DPRRegClassID: case ARM::DPR_VFP2RegClassID: return ARM::D15; > + case ARM::QPRRegClassID: return ARM::Q15; > + case ARM::SPRRegClassID: case ARM::SPR_8RegClassID: return ARM::S15; > + } > + break; > + case 16: > + switch (RegClassID) { > + case ARM::DPRRegClassID: return ARM::D16; > + case ARM::SPRRegClassID: return ARM::S16; > + } > + break; > + case 17: > + switch (RegClassID) { > + case ARM::DPRRegClassID: return ARM::D17; > + case ARM::SPRRegClassID: return ARM::S17; > + } > + break; > + case 18: > + switch (RegClassID) { > + case ARM::DPRRegClassID: return ARM::D18; > + case ARM::SPRRegClassID: return ARM::S18; > + } > + break; > + case 19: > + switch (RegClassID) { > + case ARM::DPRRegClassID: return ARM::D19; > + case ARM::SPRRegClassID: return ARM::S19; > + } > + break; > + case 20: > + switch (RegClassID) { > + case ARM::DPRRegClassID: return ARM::D20; > + case ARM::SPRRegClassID: return ARM::S20; > + } > + break; > + case 21: > + switch (RegClassID) { > + case ARM::DPRRegClassID: return ARM::D21; > + case ARM::SPRRegClassID: return ARM::S21; > + } > + break; > + case 22: > + switch (RegClassID) { > + case ARM::DPRRegClassID: return ARM::D22; > + case ARM::SPRRegClassID: return ARM::S22; > + } > + break; > + case 23: > + switch (RegClassID) { > + case ARM::DPRRegClassID: return ARM::D23; > + case ARM::SPRRegClassID: return ARM::S23; > + } > + break; > + case 24: > + switch (RegClassID) { > + case ARM::DPRRegClassID: return ARM::D24; > + case ARM::SPRRegClassID: return ARM::S24; > + } > + break; > + case 25: > + switch (RegClassID) { > + case ARM::DPRRegClassID: return ARM::D25; > + case ARM::SPRRegClassID: return ARM::S25; > + } > + break; > + case 26: > + switch (RegClassID) { > + case ARM::DPRRegClassID: return ARM::D26; > + case ARM::SPRRegClassID: return ARM::S26; > + } > + break; > + case 27: > + switch (RegClassID) { > + case ARM::DPRRegClassID: return ARM::D27; > + case ARM::SPRRegClassID: return ARM::S27; > + } > + break; > + case 28: > + switch (RegClassID) { > + case ARM::DPRRegClassID: return ARM::D28; > + case ARM::SPRRegClassID: return ARM::S28; > + } > + break; > + case 29: > + switch (RegClassID) { > + case ARM::DPRRegClassID: return ARM::D29; > + case ARM::SPRRegClassID: return ARM::S29; > + } > + break; > + case 30: > + switch (RegClassID) { > + case ARM::DPRRegClassID: return ARM::D30; > + case ARM::SPRRegClassID: return ARM::S30; > + } > + break; > + case 31: > + switch (RegClassID) { > + case ARM::DPRRegClassID: return ARM::D31; > + case ARM::SPRRegClassID: return ARM::S31; > + } > + break; > + } > + llvm_unreachable("Invalid (RegClassID, RawRegister) combination"); > +} > + > +// This is efficient but fragile. > +/* > +// See ARMGenRegisterInfo.h.inc for more info. > +static const TargetRegisterClass* const ARMRegisterClasses[] = { > + NULL, > + &ARM::CCRRegClass, // CCRRegClassID = 1, > + &ARM::DPRRegClass, // DPRRegClassID = 2, > + &ARM::DPR_8RegClass, // DPR_8RegClassID = 3, > + &ARM::DPR_VFP2RegClass, // DPR_VFP2RegClassID = 4, > + &ARM::GPRRegClass, // GPRRegClassID = 5, > + &ARM::QPRRegClass, // QPRRegClassID = 6, > + &ARM::QPR_8RegClass, // QPR_8RegClassID = 7, > + &ARM::QPR_VFP2RegClass, // QPR_VFP2RegClassID = 8, > + &ARM::SPRRegClass, // SPRRegClassID = 9, > + &ARM::SPR_8RegClass, // SPR_8RegClassID = 10, > + &ARM::SPR_INVALIDRegClass, // SPR_INVALIDRegClassID = 11, > + &ARM::tGPRRegClass, // tGPRRegClassID = 12 > +}; > + > +// Return the register enum given register class id and raw register value. > +static unsigned getRegisterEnum(unsigned RegClassID, unsigned RawRegister) { > + assert(RegClassID < array_lengthof(ARMRegisterClasses) && > + "Register Class ID out of range"); > + return ARMRegisterClasses[RegClassID]->getRegister(RawRegister); > +} > +*/ > + > +/// DisassembleFP - DisassembleFP points to a function that disassembles an insn > +/// and builds the MCOperand list upon disassembly. It returns false on failure > +/// or true on success. The number of operands added is updated upon success. > +typedef bool (*DisassembleFP)(MCInst &MI, unsigned Opcode, uint32_t insn, > + unsigned short NumOps, unsigned &NumOpsAdded); > + > +/////////////////////////////// > +// // > +// Utility Functions // > +// // > +/////////////////////////////// > + > +// Extract/Decode Rd: Inst{15-12}. > +static inline unsigned decodeRd(uint32_t insn) { > + return (insn >> ARMII::RegRdShift) & ARMII::GPRRegMask; > +} > + > +// Extract/Decode Rn: Inst{19-16}. > +static inline unsigned decodeRn(uint32_t insn) { > + return (insn >> ARMII::RegRnShift) & ARMII::GPRRegMask; > +} > + > +// Extract/Decode Rm: Inst{3-0}. > +static inline unsigned decodeRm(uint32_t insn) { > + return (insn & ARMII::GPRRegMask); > +} > + > +// Extract/Decode Rs: Inst{11-8}. > +static inline unsigned decodeRs(uint32_t insn) { > + return (insn >> ARMII::RegRsShift) & ARMII::GPRRegMask; > +} > + > +static inline unsigned getCondField(uint32_t insn) { > + return (insn >> ARMII::CondShift); > +} > + > +static inline unsigned getIBit(uint32_t insn) { > + return (insn >> ARMII::I_BitShift) & 1; > +} > + > +static inline unsigned getAM3IBit(uint32_t insn) { > + return (insn >> ARMII::AM3_I_BitShift) & 1; > +} > + > +static inline unsigned getPBit(uint32_t insn) { > + return (insn >> ARMII::P_BitShift) & 1; > +} > + > +static inline unsigned getUBit(uint32_t insn) { > + return (insn >> ARMII::U_BitShift) & 1; > +} > + > +static inline unsigned getPUBits(uint32_t insn) { > + return (insn >> ARMII::U_BitShift) & 3; > +} > + > +static inline unsigned getSBit(uint32_t insn) { > + return (insn >> ARMII::S_BitShift) & 1; > +} > + > +static inline unsigned getWBit(uint32_t insn) { > + return (insn >> ARMII::W_BitShift) & 1; > +} > + > +static inline unsigned getDBit(uint32_t insn) { > + return (insn >> ARMII::D_BitShift) & 1; > +} > + > +static inline unsigned getNBit(uint32_t insn) { > + return (insn >> ARMII::N_BitShift) & 1; > +} > + > +static inline unsigned getMBit(uint32_t insn) { > + return (insn >> ARMII::M_BitShift) & 1; > +} > + > +namespace { > +// Sign extend 5 bit number x to r. > +// Usage: int r = signextend(x); > +template inline T signextend(const T x) { > + struct {T x:B;} s; > + return s.x = x; > +} > +} > + > +// See A8.4 Shifts applied to a register. > +// A8.4.2 Register controlled shifts. > +// > +// getShiftOpcForBits - getShiftOpcForBits translates from the ARM encoding bits > +// into llvm enums for shift opcode. > +// > +// A8-12: DecodeRegShift() > +static inline ARM_AM::ShiftOpc getShiftOpcForBits(unsigned bits) { > + switch (bits) { > + default: assert(0 && "No such value"); > + case 0: return ARM_AM::lsl; > + case 1: return ARM_AM::lsr; > + case 2: return ARM_AM::asr; > + case 3: return ARM_AM::ror; > + } > +} > + > +// See A8.4 Shifts applied to a register. > +// A8.4.1 Constant shifts. > +// > +// getImmShiftSE - getImmShiftSE translates from the raw ShiftOpc and raw Imm5 > +// encodings into the intended ShiftOpc and shift amount. > +// > +// A8-11: DecodeImmShift() > +static inline void getImmShiftSE(ARM_AM::ShiftOpc &ShOp, unsigned &ShImm) { > + // If type == 0b11 and imm5 == 0, we have an rrx, instead. > + if (ShOp == ARM_AM::ror && ShImm == 0) > + ShOp = ARM_AM::rrx; > + // If (lsr or asr) and imm5 == 0, shift amount is 32. > + if ((ShOp == ARM_AM::lsr || ShOp == ARM_AM::asr) && ShImm == 0) > + ShImm = 32; > +} > + > +// getAMSubModeForBits - getAMSubModeForBits translates from the ARM encoding > +// bits Inst{24-23} (P(24) and U(23)) into llvm enums for AMSubMode. > +static inline ARM_AM::AMSubMode getAMSubModeForBits(unsigned bits) { > + switch (bits) { > + default: assert(0 && "No such value"); > + case 1: return ARM_AM::ia; // P=0 U=1 > + case 3: return ARM_AM::ib; // P=1 U=1 > + case 0: return ARM_AM::da; // P=0 U=0 > + case 2: return ARM_AM::db; // P=1 U=0 > + } > +} > + > +//////////////////////////////////////////// > +// // > +// Disassemble function definitions // > +// // > +//////////////////////////////////////////// > + > +/// There is a separate Disassemble*Frm function entry for disassembly of an ARM > +/// instr into a list of MCOperands in the appropriate order, with possible dst, > +/// followed by possible src(s). > +/// > +/// The processing of the predicate, and the 'S' modifier bit, if MI modifies > +/// the CPSR, is factored into ARMBasicMCBuilder's class method named > +/// TryPredicateAndSBitModifier. > + > +static bool DisassemblePseudo(MCInst &MI, unsigned Opcode, uint32_t insn, > + unsigned short NumOps, unsigned &NumOpsAdded) { > + > + if (Opcode == ARM::Int_MemBarrierV7 || Opcode == ARM::Int_SyncBarrierV7) > + return true; > + > + assert(0 && "Unexpected pseudo instruction!"); > + return false; > +} > + > +// Multiply Instructions. > +// MLA, MLS, SMLABB, SMLABT, SMLATB, SMLATT, SMLAWB, SMLAWT, SMMLA, SMMLS: > +// Rd{19-16} Rn{3-0} Rm{11-8} Ra{15-12} > +// > +// MUL, SMMUL, SMULBB, SMULBT, SMULTB, SMULTT, SMULWB, SMULWT: > +// Rd{19-16} Rn{3-0} Rm{11-8} > +// > +// SMLAL, SMULL, UMAAL, UMLAL, UMULL, SMLALBB, SMLALBT, SMLALTB, SMLALTT: > +// RdLo{15-12} RdHi{19-16} Rn{3-0} Rm{11-8} > +// > +// The mapping of the multiply registers to the "regular" ARM registers, where > +// there are convenience decoder functions, is: > +// > +// Inst{15-12} => Rd > +// Inst{19-16} => Rn > +// Inst{3-0} => Rm > +// Inst{11-8} => Rs > +static bool DisassembleMulFrm(MCInst &MI, unsigned Opcode, uint32_t insn, > + unsigned short NumOps, unsigned &NumOpsAdded) { > + > + const TargetInstrDesc &TID = ARMInsts[Opcode]; > + unsigned short NumDefs = TID.getNumDefs(); > + const TargetOperandInfo *OpInfo = TID.OpInfo; > + unsigned &OpIdx = NumOpsAdded; > + > + OpIdx = 0; > + > + assert(NumDefs > 0 && "NumDefs should be greater than 0 for MulFrm"); > + assert(NumOps >= 3 > + && OpInfo[0].RegClass == ARM::GPRRegClassID > + && OpInfo[1].RegClass == ARM::GPRRegClassID > + && OpInfo[2].RegClass == ARM::GPRRegClassID); > + > + // Instructions with two destination registers have RdLo{15-12} first. > + if (NumDefs == 2) { > + assert(NumOps >= 4 && OpInfo[3].RegClass == ARM::GPRRegClassID); > + MI.addOperand(MCOperand::CreateReg(getRegisterEnum(ARM::GPRRegClassID, > + decodeRd(insn)))); > + ++OpIdx; > + } > + > + // The destination register: RdHi{19-16} or Rd{19-16}. > + MI.addOperand(MCOperand::CreateReg(getRegisterEnum(ARM::GPRRegClassID, > + decodeRn(insn)))); > + > + // The two src regsiters: Rn{3-0}, then Rm{11-8}. > + MI.addOperand(MCOperand::CreateReg(getRegisterEnum(ARM::GPRRegClassID, > + decodeRm(insn)))); > + MI.addOperand(MCOperand::CreateReg(getRegisterEnum(ARM::GPRRegClassID, > + decodeRs(insn)))); > + OpIdx += 3; > + > + // Many multiply instructions (e.g., MLA) have three src registers. > + // The third register operand is Ra{15-12}. > + if (OpIdx < NumOps && OpInfo[OpIdx].RegClass == ARM::GPRRegClassID) { > + MI.addOperand(MCOperand::CreateReg(getRegisterEnum(ARM::GPRRegClassID, > + decodeRd(insn)))); > + ++OpIdx; > + } > + > + return true; > +} > + > +// Helper routines for disassembly of coprocessor instructions. > + > +static bool LdStCopOpcode(unsigned Opcode) { > + if ((Opcode >= ARM::LDC2L_OFFSET && Opcode <= ARM::LDC_PRE) || > + (Opcode >= ARM::STC2L_OFFSET && Opcode <= ARM::STC_PRE)) > + return true; > + return false; > +} > +static bool CoprocessorOpcode(unsigned Opcode) { > + if (LdStCopOpcode(Opcode)) > + return true; > + > + switch (Opcode) { > + default: > + return false; > + case ARM::CDP: case ARM::CDP2: > + case ARM::MCR: case ARM::MCR2: case ARM::MRC: case ARM::MRC2: > + case ARM::MCRR: case ARM::MCRR2: case ARM::MRRC: case ARM::MRRC2: > + return true; > + } > +} > +static inline unsigned GetCoprocessor(uint32_t insn) { > + return slice(insn, 11, 8); > +} > +static inline unsigned GetCopOpc1(uint32_t insn, bool CDP) { > + return CDP ? slice(insn, 23, 20) : slice(insn, 23, 21); > +} > +static inline unsigned GetCopOpc2(uint32_t insn) { > + return slice(insn, 7, 5); > +} > +static inline unsigned GetCopOpc(uint32_t insn) { > + return slice(insn, 7, 4); > +} > +// Most of the operands are in immediate forms, except Rd and Rn, which are ARM > +// core registers. > +// > +// CDP, CDP2: cop opc1 CRd CRn CRm opc2 > +// > +// MCR, MCR2, MRC, MRC2: cop opc1 Rd CRn CRm opc2 > +// > +// MCRR, MCRR2, MRRC, MRRc2: cop opc Rd Rn CRm > +// > +// LDC_OFFSET, LDC_PRE, LDC_POST: cop CRd Rn R0 [+/-]imm8:00 > +// and friends > +// STC_OFFSET, STC_PRE, STC_POST: cop CRd Rn R0 [+/-]imm8:00 > +// and friends > +// <-- addrmode2 --> > +// > +// LDC_OPTION: cop CRd Rn imm8 > +// and friends > +// STC_OPTION: cop CRd Rn imm8 > +// and friends > +// > +static bool DisassembleCoprocessor(MCInst &MI, unsigned Opcode, uint32_t insn, > + unsigned short NumOps, unsigned &NumOpsAdded) { > + > + assert(NumOps >= 5); > + > + unsigned &OpIdx = NumOpsAdded; > + bool OneCopOpc = (Opcode == ARM::MCRR || Opcode == ARM::MCRR2 || > + Opcode == ARM::MRRC || Opcode == ARM::MRRC2); > + // CDP/CDP2 has no GPR operand; the opc1 operand is also wider (Inst{23-20}). > + bool NoGPR = (Opcode == ARM::CDP || Opcode == ARM::CDP2); > + bool LdStCop = LdStCopOpcode(Opcode); > + > + OpIdx = 0; > + > + MI.addOperand(MCOperand::CreateImm(GetCoprocessor(insn))); > + > + if (LdStCop) { > + // Unindex if P:W = 0b00 --> _OPTION variant > + unsigned PW = getPBit(insn) << 1 | getWBit(insn); > + > + MI.addOperand(MCOperand::CreateImm(decodeRd(insn))); > + > + MI.addOperand(MCOperand::CreateReg(getRegisterEnum(ARM::GPRRegClassID, > + decodeRn(insn)))); > + > + if (PW) { > + MI.addOperand(MCOperand::CreateReg(0)); > + ARM_AM::AddrOpc AddrOpcode = getUBit(insn) ? ARM_AM::add : ARM_AM::sub; > + unsigned Offset = ARM_AM::getAM2Opc(AddrOpcode, slice(insn, 7, 0) << 2, > + ARM_AM::no_shift); > + MI.addOperand(MCOperand::CreateImm(Offset)); > + OpIdx = 5; > + } else { > + MI.addOperand(MCOperand::CreateImm(slice(insn, 7, 0))); > + OpIdx = 4; > + } > + } else { > + MI.addOperand(MCOperand::CreateImm(OneCopOpc ? GetCopOpc(insn) > + : GetCopOpc1(insn, NoGPR))); > + > + MI.addOperand(NoGPR ? MCOperand::CreateImm(decodeRd(insn)) > + : MCOperand::CreateReg( > + getRegisterEnum(ARM::GPRRegClassID, > + decodeRd(insn)))); > + > + MI.addOperand(OneCopOpc ? MCOperand::CreateReg( > + getRegisterEnum(ARM::GPRRegClassID, > + decodeRn(insn))) > + : MCOperand::CreateImm(decodeRn(insn))); > + > + MI.addOperand(MCOperand::CreateImm(decodeRm(insn))); > + > + OpIdx = 5; > + > + if (!OneCopOpc) { > + MI.addOperand(MCOperand::CreateImm(GetCopOpc2(insn))); > + ++OpIdx; > + } > + } > + > + return true; > +} > + > +// Branch Instructions. > +// BLr9: SignExtend(Imm24:'00', 32) > +// Bcc, BLr9_pred: SignExtend(Imm24:'00', 32) Pred0 Pred1 > +// SMC: ZeroExtend(imm4, 32) > +// SVC: ZeroExtend(Imm24, 32) > +// > +// Various coprocessor instructions are assigned BrFrm arbitrarily. > +// Delegates to DisassembleCoprocessor() helper function. > +// > +// MRS/MRSsys: Rd > +// MSR/MSRsys: Rm mask=Inst{19-16} > +// BXJ: Rm > +// MSRi/MSRsysi: so_imm > +// SRSW/SRS: addrmode4:$addr mode_imm > +// RFEW/RFE: addrmode4:$addr Rn > +static bool DisassembleBrFrm(MCInst &MI, unsigned Opcode, uint32_t insn, > + unsigned short NumOps, unsigned &NumOpsAdded) { > + > + if (CoprocessorOpcode(Opcode)) > + return DisassembleCoprocessor(MI, Opcode, insn, NumOps, NumOpsAdded); > + > + const TargetOperandInfo *OpInfo = ARMInsts[Opcode].OpInfo; > + > + // MRS and MRSsys take one GPR reg Rd. > + if (Opcode == ARM::MRS || Opcode == ARM::MRSsys) { > + assert(NumOps >= 1 && OpInfo[0].RegClass == ARM::GPRRegClassID); > + MI.addOperand(MCOperand::CreateReg(getRegisterEnum(ARM::GPRRegClassID, > + decodeRd(insn)))); > + NumOpsAdded = 1; > + return true; > + } > + // BXJ takes one GPR reg Rm. > + if (Opcode == ARM::BXJ) { > + assert(NumOps >= 1 && OpInfo[0].RegClass == ARM::GPRRegClassID); > + MI.addOperand(MCOperand::CreateReg(getRegisterEnum(ARM::GPRRegClassID, > + decodeRm(insn)))); > + NumOpsAdded = 1; > + return true; > + } > + // MSR and MSRsys take one GPR reg Rm, followed by the mask. > + if (Opcode == ARM::MSR || Opcode == ARM::MSRsys) { > + assert(NumOps >= 1 && OpInfo[0].RegClass == ARM::GPRRegClassID); > + MI.addOperand(MCOperand::CreateReg(getRegisterEnum(ARM::GPRRegClassID, > + decodeRm(insn)))); > + MI.addOperand(MCOperand::CreateImm(slice(insn, 19, 16))); > + NumOpsAdded = 2; > + return true; > + } > + // MSRi and MSRsysi take one so_imm operand, followed by the mask. > + if (Opcode == ARM::MSRi || Opcode == ARM::MSRsysi) { > + // SOImm is 4-bit rotate amount in bits 11-8 with 8-bit imm in bits 7-0. > + // A5.2.4 Rotate amount is twice the numeric value of Inst{11-8}. > + // See also ARMAddressingModes.h: getSOImmValImm() and getSOImmValRot(). > + unsigned Rot = (insn >> ARMII::SoRotImmShift) & 0xF; > + unsigned Imm = insn & 0xFF; > + MI.addOperand(MCOperand::CreateImm(ARM_AM::rotr32(Imm, 2*Rot))); > + MI.addOperand(MCOperand::CreateImm(slice(insn, 19, 16))); > + NumOpsAdded = 2; > + return true; > + } > + // SRSW and SRS requires addrmode4:$addr for ${addr:submode}, followed by the > + // mode immediate (Inst{4-0}). > + if (Opcode == ARM::SRSW || Opcode == ARM::SRS || > + Opcode == ARM::RFEW || Opcode == ARM::RFE) { > + // ARMInstPrinter::printAddrMode4Operand() prints special mode string > + // if the base register is SP; so don't set ARM::SP. > + MI.addOperand(MCOperand::CreateReg(0)); > + bool WB = (Opcode == ARM::SRSW); > + ARM_AM::AMSubMode SubMode = getAMSubModeForBits(getPUBits(insn)); > + MI.addOperand(MCOperand::CreateImm(ARM_AM::getAM4ModeImm(SubMode, WB))); > + > + if (Opcode == ARM::SRSW || Opcode == ARM::SRS) > + MI.addOperand(MCOperand::CreateImm(slice(insn, 4, 0))); > + else > + MI.addOperand(MCOperand::CreateReg(getRegisterEnum(ARM::GPRRegClassID, > + decodeRn(insn)))); > + NumOpsAdded = 3; > + return true; > + } > + > + assert(Opcode == ARM::Bcc || Opcode == ARM::BLr9 || Opcode == ARM::BLr9_pred > + || Opcode == ARM::SMC || Opcode == ARM::SVC); > + > + assert(NumOps >= 1 && OpInfo[0].RegClass == 0); > + > + int Imm32 = 0; > + if (Opcode == ARM::SMC) { > + // ZeroExtend(imm4, 32) where imm24 = Inst{3-0}. > + Imm32 = slice(insn, 3, 0); > + } else if (Opcode == ARM::SVC) { > + // ZeroExtend(imm24, 32) where imm24 = Inst{23-0}. > + Imm32 = slice(insn, 23, 0); > + } else { > + // SignExtend(imm24:'00', 32) where imm24 = Inst{23-0}. > + unsigned Imm26 = slice(insn, 23, 0) << 2; > + Imm32 = signextend(Imm26); > + > + // When executing an ARM instruction, PC reads as the address of the current > + // instruction plus 8. The assembler subtracts 8 from the difference > + // between the branch instruction and the target address, disassembler has > + // to add 8 to compensate. > + Imm32 += 8; > + } > + > + MI.addOperand(MCOperand::CreateImm(Imm32)); > + NumOpsAdded = 1; > + > + return true; > +} > + > +// Misc. Branch Instructions. > +// BR_JTadd, BR_JTr, BR_JTm > +// BLXr9, BXr9 > +// BRIND, BX_RET > +static bool DisassembleBrMiscFrm(MCInst &MI, unsigned Opcode, uint32_t insn, > + unsigned short NumOps, unsigned &NumOpsAdded) { > + > + const TargetOperandInfo *OpInfo = ARMInsts[Opcode].OpInfo; > + unsigned &OpIdx = NumOpsAdded; > + > + OpIdx = 0; > + > + // BX_RET has only two predicate operands, do an early return. > + if (Opcode == ARM::BX_RET) > + return true; > + > + // BLXr9 and BRIND take one GPR reg. > + if (Opcode == ARM::BLXr9 || Opcode == ARM::BRIND) { > + assert(NumOps >= 1 && OpInfo[OpIdx].RegClass == ARM::GPRRegClassID); > + MI.addOperand(MCOperand::CreateReg(getRegisterEnum(ARM::GPRRegClassID, > + decodeRm(insn)))); > + OpIdx = 1; > + return true; > + } > + > + // BR_JTadd is an ADD with Rd = PC, (Rn, Rm) as the target and index regs. > + if (Opcode == ARM::BR_JTadd) { > + // InOperandList with GPR:$target and GPR:$idx regs. > + > + assert(NumOps == 4); > + MI.addOperand(MCOperand::CreateReg(getRegisterEnum(ARM::GPRRegClassID, > + decodeRn(insn)))); > + MI.addOperand(MCOperand::CreateReg(getRegisterEnum(ARM::GPRRegClassID, > + decodeRm(insn)))); > + > + // Fill in the two remaining imm operands to signify build completion. > + MI.addOperand(MCOperand::CreateImm(0)); > + MI.addOperand(MCOperand::CreateImm(0)); > + > + OpIdx = 4; > + return true; > + } > + > + // BR_JTr is a MOV with Rd = PC, and Rm as the source register. > + if (Opcode == ARM::BR_JTr) { > + // InOperandList with GPR::$target reg. > + > + assert(NumOps == 3); > + MI.addOperand(MCOperand::CreateReg(getRegisterEnum(ARM::GPRRegClassID, > + decodeRm(insn)))); > + > + // Fill in the two remaining imm operands to signify build completion. > + MI.addOperand(MCOperand::CreateImm(0)); > + MI.addOperand(MCOperand::CreateImm(0)); > + > + OpIdx = 3; > + return true; > + } > + > + // BR_JTm is an LDR with Rt = PC. > + if (Opcode == ARM::BR_JTm) { > + // This is the reg/reg form, with base reg followed by +/- reg shop imm. > + // See also ARMAddressingModes.h (Addressing Mode #2). > + > + assert(NumOps == 5 && getIBit(insn) == 1); > + MI.addOperand(MCOperand::CreateReg(getRegisterEnum(ARM::GPRRegClassID, > + decodeRn(insn)))); > + > + ARM_AM::AddrOpc AddrOpcode = getUBit(insn) ? ARM_AM::add : ARM_AM::sub; > + > + // Disassemble the offset reg (Rm), shift type, and immediate shift length. > + MI.addOperand(MCOperand::CreateReg(getRegisterEnum(ARM::GPRRegClassID, > + decodeRm(insn)))); > + // Inst{6-5} encodes the shift opcode. > + ARM_AM::ShiftOpc ShOp = getShiftOpcForBits(slice(insn, 6, 5)); > + // Inst{11-7} encodes the imm5 shift amount. > + unsigned ShImm = slice(insn, 11, 7); > + > + // A8.4.1. Possible rrx or shift amount of 32... > + getImmShiftSE(ShOp, ShImm); > + MI.addOperand(MCOperand::CreateImm( > + ARM_AM::getAM2Opc(AddrOpcode, ShImm, ShOp))); > + > + // Fill in the two remaining imm operands to signify build completion. > + MI.addOperand(MCOperand::CreateImm(0)); > + MI.addOperand(MCOperand::CreateImm(0)); > + > + OpIdx = 5; > + return true; > + } > + > + assert(0 && "Unexpected BrMiscFrm Opcode"); > + return false; > +} > + > +static inline uint32_t getBFCInvMask(uint32_t insn) { > + uint32_t lsb = slice(insn, 11, 7); > + uint32_t msb = slice(insn, 20, 16); > + uint32_t Val = 0; > + assert(lsb <= msb && "Encoding error: lsb > msb"); > + for (uint32_t i = lsb; i <= msb; ++i) > + Val |= (1 << i); > + return ~Val; > +} > + > +static inline bool SaturateOpcode(unsigned Opcode) { > + switch (Opcode) { > + case ARM::SSATlsl: case ARM::SSATasr: case ARM::SSAT16: > + case ARM::USATlsl: case ARM::USATasr: case ARM::USAT16: > + return true; > + default: > + return false; > + } > +} > + > +static inline unsigned decodeSaturatePos(unsigned Opcode, uint32_t insn) { > + switch (Opcode) { > + case ARM::SSATlsl: > + case ARM::SSATasr: > + return slice(insn, 20, 16) + 1; > + case ARM::SSAT16: > + return slice(insn, 19, 16) + 1; > + case ARM::USATlsl: > + case ARM::USATasr: > + return slice(insn, 20, 16); > + case ARM::USAT16: > + return slice(insn, 19, 16); > + default: > + llvm_unreachable("Invalid opcode passed in"); > + return 0; > + } > +} > + > +// A major complication is the fact that some of the saturating add/subtract > +// operations have Rd Rm Rn, instead of the "normal" Rd Rn Rm. > +// They are QADD, QDADD, QDSUB, and QSUB. > +static bool DisassembleDPFrm(MCInst &MI, unsigned Opcode, uint32_t insn, > + unsigned short NumOps, unsigned &NumOpsAdded) { > + > + const TargetInstrDesc &TID = ARMInsts[Opcode]; > + unsigned short NumDefs = TID.getNumDefs(); > + bool isUnary = isUnaryDP(TID.TSFlags); > + const TargetOperandInfo *OpInfo = TID.OpInfo; > + unsigned &OpIdx = NumOpsAdded; > + > + OpIdx = 0; > + > + // Disassemble register def if there is one. > + if (NumDefs && (OpInfo[OpIdx].RegClass == ARM::GPRRegClassID)) { > + MI.addOperand(MCOperand::CreateReg(getRegisterEnum(ARM::GPRRegClassID, > + decodeRd(insn)))); > + ++OpIdx; > + } > + > + // Now disassemble the src operands. > + if (OpIdx >= NumOps) > + return false; > + > + // SSAT/SSAT16/USAT/USAT16 has imm operand after Rd. > + if (SaturateOpcode(Opcode)) { > + MI.addOperand(MCOperand::CreateImm(decodeSaturatePos(Opcode, insn))); > + > + MI.addOperand(MCOperand::CreateReg(getRegisterEnum(ARM::GPRRegClassID, > + decodeRm(insn)))); > + > + if (Opcode == ARM::SSAT16 || Opcode == ARM::USAT16) { > + OpIdx += 2; > + return true; > + } > + > + // For SSAT operand reg (Rm) has been disassembled above. > + // Now disassemble the shift amount. > + > + // Inst{11-7} encodes the imm5 shift amount. > + unsigned ShAmt = slice(insn, 11, 7); > + > + // A8.6.183. Possible ASR shift amount of 32... > + if (Opcode == ARM::SSATasr && ShAmt == 0) > + ShAmt = 32; > + > + MI.addOperand(MCOperand::CreateImm(ShAmt)); > + > + OpIdx += 3; > + return true; > + } > + > + // Special-case handling of BFC/BFI/SBFX/UBFX. > + if (Opcode == ARM::BFC || Opcode == ARM::BFI) { > + // TIED_TO operand skipped for BFC and Inst{3-0} (Reg) for BFI. > + MI.addOperand(MCOperand::CreateReg(Opcode == ARM::BFC ? 0 > + : getRegisterEnum(ARM::GPRRegClassID, > + decodeRm(insn)))); > + MI.addOperand(MCOperand::CreateImm(getBFCInvMask(insn))); > + OpIdx += 2; > + return true; > + } > + if (Opcode == ARM::SBFX || Opcode == ARM::UBFX) { > + MI.addOperand(MCOperand::CreateReg(getRegisterEnum(ARM::GPRRegClassID, > + decodeRm(insn)))); > + MI.addOperand(MCOperand::CreateImm(slice(insn, 11, 7))); > + MI.addOperand(MCOperand::CreateImm(slice(insn, 20, 16) + 1)); > + OpIdx += 3; > + return true; > + } > + > + bool RmRn = (Opcode == ARM::QADD || Opcode == ARM::QDADD || > + Opcode == ARM::QDSUB || Opcode == ARM::QSUB); > + > + // BinaryDP has an Rn operand. > + if (!isUnary) { > + assert(OpInfo[OpIdx].RegClass == ARM::GPRRegClassID); > + MI.addOperand(MCOperand::CreateReg( > + getRegisterEnum(ARM::GPRRegClassID, > + RmRn ? decodeRm(insn) : decodeRn(insn)))); > + ++OpIdx; > + } > + > + // If this is a two-address operand, skip it, e.g., MOVCCr operand 1. > + if (isUnary && (TID.getOperandConstraint(OpIdx, TOI::TIED_TO) != -1)) { > + MI.addOperand(MCOperand::CreateReg(0)); > + ++OpIdx; > + } > + > + // Now disassemble operand 2. > + if (OpIdx >= NumOps) > + return false; > + > + if (OpInfo[OpIdx].RegClass == ARM::GPRRegClassID) { > + // We have a reg/reg form. > + // Assert disabled because saturating operations, e.g., A8.6.127 QASX, are > + // routed here as well. > + // assert(getIBit(insn) == 0 && "I_Bit != '0' reg/reg form"); > + MI.addOperand(MCOperand::CreateReg( > + getRegisterEnum(ARM::GPRRegClassID, > + RmRn? decodeRn(insn) : decodeRm(insn)))); > + ++OpIdx; > + } else if (Opcode == ARM::MOVi16 || Opcode == ARM::MOVTi16) { > + // We have an imm16 = imm4:imm12 (imm4=Inst{19:16}, imm12 = Inst{11:0}). > + assert(getIBit(insn) == 1 && "I_Bit != '1' reg/imm form"); > + unsigned Imm16 = slice(insn, 19, 16) << 12 | slice(insn, 11, 0); > + MI.addOperand(MCOperand::CreateImm(Imm16)); > + ++OpIdx; > + } else { > + // We have a reg/imm form. > + // SOImm is 4-bit rotate amount in bits 11-8 with 8-bit imm in bits 7-0. > + // A5.2.4 Rotate amount is twice the numeric value of Inst{11-8}. > + // See also ARMAddressingModes.h: getSOImmValImm() and getSOImmValRot(). > + assert(getIBit(insn) == 1 && "I_Bit != '1' reg/imm form"); > + unsigned Rot = (insn >> ARMII::SoRotImmShift) & 0xF; > + unsigned Imm = insn & 0xFF; > + MI.addOperand(MCOperand::CreateImm(ARM_AM::rotr32(Imm, 2*Rot))); > + ++OpIdx; > + } > + > + return true; > +} > + > +static bool DisassembleDPSoRegFrm(MCInst &MI, unsigned Opcode, uint32_t insn, > + unsigned short NumOps, unsigned &NumOpsAdded) { > + > + const TargetInstrDesc &TID = ARMInsts[Opcode]; > + unsigned short NumDefs = TID.getNumDefs(); > + bool isUnary = isUnaryDP(TID.TSFlags); > + const TargetOperandInfo *OpInfo = TID.OpInfo; > + unsigned &OpIdx = NumOpsAdded; > + > + OpIdx = 0; > + > + // Disassemble register def if there is one. > + if (NumDefs && (OpInfo[OpIdx].RegClass == ARM::GPRRegClassID)) { > + MI.addOperand(MCOperand::CreateReg(getRegisterEnum(ARM::GPRRegClassID, > + decodeRd(insn)))); > + ++OpIdx; > + } > + > + // Disassemble the src operands. > + if (OpIdx >= NumOps) > + return false; > + > + // BinaryDP has an Rn operand. > + if (!isUnary) { > + assert(OpInfo[OpIdx].RegClass == ARM::GPRRegClassID); > + MI.addOperand(MCOperand::CreateReg(getRegisterEnum(ARM::GPRRegClassID, > + decodeRn(insn)))); > + ++OpIdx; > + } > + > + // If this is a two-address operand, skip it, e.g., MOVCCs operand 1. > + if (isUnary && (TID.getOperandConstraint(OpIdx, TOI::TIED_TO) != -1)) { > + MI.addOperand(MCOperand::CreateReg(0)); > + ++OpIdx; > + } > + > + // Disassemble operand 2, which consists of three components. > + if (OpIdx + 2 >= NumOps) > + return false; > + > + assert((OpInfo[OpIdx].RegClass == ARM::GPRRegClassID) && > + (OpInfo[OpIdx+1].RegClass == ARM::GPRRegClassID) && > + (OpInfo[OpIdx+2].RegClass == 0)); > + > + // Register-controlled shifts have Inst{7} = 0 and Inst{4} = 1. > + unsigned Rs = slice(insn, 4, 4); > + > + MI.addOperand(MCOperand::CreateReg(getRegisterEnum(ARM::GPRRegClassID, > + decodeRm(insn)))); > + if (Rs) { > + // Register-controlled shifts: [Rm, Rs, shift]. > + MI.addOperand(MCOperand::CreateReg(getRegisterEnum(ARM::GPRRegClassID, > + decodeRs(insn)))); > + // Inst{6-5} encodes the shift opcode. > + ARM_AM::ShiftOpc ShOp = getShiftOpcForBits(slice(insn, 6, 5)); > + MI.addOperand(MCOperand::CreateImm(ARM_AM::getSORegOpc(ShOp, 0))); > + } else { > + // Constant shifts: [Rm, reg0, shift_imm]. > + MI.addOperand(MCOperand::CreateReg(0)); // NoRegister > + // Inst{6-5} encodes the shift opcode. > + ARM_AM::ShiftOpc ShOp = getShiftOpcForBits(slice(insn, 6, 5)); > + // Inst{11-7} encodes the imm5 shift amount. > + unsigned ShImm = slice(insn, 11, 7); > + > + // A8.4.1. Possible rrx or shift amount of 32... > + getImmShiftSE(ShOp, ShImm); > + MI.addOperand(MCOperand::CreateImm(ARM_AM::getSORegOpc(ShOp, ShImm))); > + } > + OpIdx += 3; > + > + return true; > +} > + > +static bool DisassembleLdStFrm(MCInst &MI, unsigned Opcode, uint32_t insn, > + unsigned short NumOps, unsigned &NumOpsAdded, bool isStore) { > + > + const TargetInstrDesc &TID = ARMInsts[Opcode]; > + unsigned short NumDefs = TID.getNumDefs(); > + bool isPrePost = isPrePostLdSt(TID.TSFlags); > + const TargetOperandInfo *OpInfo = TID.OpInfo; > + unsigned &OpIdx = NumOpsAdded; > + > + OpIdx = 0; > + > + assert((!isStore && NumDefs > 0) || (isStore && (NumDefs == 0 || isPrePost))); > + > + // Operand 0 of a pre- and post-indexed store is the address base writeback. > + if (isPrePost && isStore) { > + assert(OpInfo[OpIdx].RegClass == ARM::GPRRegClassID); > + MI.addOperand(MCOperand::CreateReg(getRegisterEnum(ARM::GPRRegClassID, > + decodeRn(insn)))); > + ++OpIdx; > + } > + > + // Disassemble the dst/src operand. > + if (OpIdx >= NumOps) > + return false; > + > + assert(OpInfo[OpIdx].RegClass == ARM::GPRRegClassID); > + MI.addOperand(MCOperand::CreateReg(getRegisterEnum(ARM::GPRRegClassID, > + decodeRd(insn)))); > + ++OpIdx; > + > + // After dst of a pre- and post-indexed load is the address base writeback. > + if (isPrePost && !isStore) { > + assert(OpInfo[OpIdx].RegClass == ARM::GPRRegClassID); > + MI.addOperand(MCOperand::CreateReg(getRegisterEnum(ARM::GPRRegClassID, > + decodeRn(insn)))); > + ++OpIdx; > + } > + > + // Disassemble the base operand. > + if (OpIdx >= NumOps) > + return false; > + > + assert(OpInfo[OpIdx].RegClass == ARM::GPRRegClassID); > + assert(!isPrePost || (TID.getOperandConstraint(OpIdx, TOI::TIED_TO) != -1)); > + MI.addOperand(MCOperand::CreateReg(getRegisterEnum(ARM::GPRRegClassID, > + decodeRn(insn)))); > + ++OpIdx; > + > + // For reg/reg form, base reg is followed by +/- reg shop imm. > + // For immediate form, it is followed by +/- imm12. > + // See also ARMAddressingModes.h (Addressing Mode #2). > + if (OpIdx + 1 >= NumOps) > + return false; > + > + assert((OpInfo[OpIdx].RegClass == ARM::GPRRegClassID) && > + (OpInfo[OpIdx+1].RegClass == 0)); > + > + ARM_AM::AddrOpc AddrOpcode = getUBit(insn) ? ARM_AM::add : ARM_AM::sub; > + if (getIBit(insn) == 0) { > + MI.addOperand(MCOperand::CreateReg(0)); > + > + // Disassemble the 12-bit immediate offset. > + unsigned Imm12 = slice(insn, 11, 0); > + unsigned Offset = ARM_AM::getAM2Opc(AddrOpcode, Imm12, ARM_AM::no_shift); > + MI.addOperand(MCOperand::CreateImm(Offset)); > + } else { > + // Disassemble the offset reg (Rm), shift type, and immediate shift length. > + MI.addOperand(MCOperand::CreateReg(getRegisterEnum(ARM::GPRRegClassID, > + decodeRm(insn)))); > + // Inst{6-5} encodes the shift opcode. > + ARM_AM::ShiftOpc ShOp = getShiftOpcForBits(slice(insn, 6, 5)); > + // Inst{11-7} encodes the imm5 shift amount. > + unsigned ShImm = slice(insn, 11, 7); > + > + // A8.4.1. Possible rrx or shift amount of 32... > + getImmShiftSE(ShOp, ShImm); > + MI.addOperand(MCOperand::CreateImm( > + ARM_AM::getAM2Opc(AddrOpcode, ShImm, ShOp))); > + } > + OpIdx += 2; > + > + return true; > +} > + > +static bool DisassembleLdFrm(MCInst &MI, unsigned Opcode, uint32_t insn, > + unsigned short NumOps, unsigned &NumOpsAdded) { > + return DisassembleLdStFrm(MI, Opcode, insn, NumOps, NumOpsAdded, false); > +} > + > +static bool DisassembleStFrm(MCInst &MI, unsigned Opcode, uint32_t insn, > + unsigned short NumOps, unsigned &NumOpsAdded) { > + return DisassembleLdStFrm(MI, Opcode, insn, NumOps, NumOpsAdded, true); > +} > + > +static bool HasDualReg(unsigned Opcode) { > + switch (Opcode) { > + default: > + return false; > + case ARM::LDRD: case ARM::LDRD_PRE: case ARM::LDRD_POST: > + case ARM::STRD: case ARM::STRD_PRE: case ARM::STRD_POST: > + return true; > + } > +} > + > +static bool DisassembleLdStMiscFrm(MCInst &MI, unsigned Opcode, uint32_t insn, > + unsigned short NumOps, unsigned &NumOpsAdded, bool isStore) { > + > + const TargetInstrDesc &TID = ARMInsts[Opcode]; > + unsigned short NumDefs = TID.getNumDefs(); > + bool isPrePost = isPrePostLdSt(TID.TSFlags); > + const TargetOperandInfo *OpInfo = TID.OpInfo; > + unsigned &OpIdx = NumOpsAdded; > + > + OpIdx = 0; > + > + assert((!isStore && NumDefs > 0) || (isStore && (NumDefs == 0 || isPrePost))); > + > + // Operand 0 of a pre- and post-indexed store is the address base writeback. > + if (isPrePost && isStore) { > + assert(OpInfo[OpIdx].RegClass == ARM::GPRRegClassID); > + MI.addOperand(MCOperand::CreateReg(getRegisterEnum(ARM::GPRRegClassID, > + decodeRn(insn)))); > + ++OpIdx; > + } > + > + bool DualReg = HasDualReg(Opcode); > + > + // Disassemble the dst/src operand. > + if (OpIdx >= NumOps) > + return false; > + > + assert(OpInfo[OpIdx].RegClass == ARM::GPRRegClassID); > + MI.addOperand(MCOperand::CreateReg(getRegisterEnum(ARM::GPRRegClassID, > + decodeRd(insn)))); > + ++OpIdx; > + > + // Fill in LDRD and STRD's second operand. > + if (DualReg) { > + MI.addOperand(MCOperand::CreateReg(getRegisterEnum(ARM::GPRRegClassID, > + decodeRd(insn) + 1))); > + ++OpIdx; > + } > + > + // After dst of a pre- and post-indexed load is the address base writeback. > + if (isPrePost && !isStore) { > + assert(OpInfo[OpIdx].RegClass == ARM::GPRRegClassID); > + MI.addOperand(MCOperand::CreateReg(getRegisterEnum(ARM::GPRRegClassID, > + decodeRn(insn)))); > + ++OpIdx; > + } > + > + // Disassemble the base operand. > + if (OpIdx >= NumOps) > + return false; > + > + assert(OpInfo[OpIdx].RegClass == ARM::GPRRegClassID); > + assert(!isPrePost || (TID.getOperandConstraint(OpIdx, TOI::TIED_TO) != -1)); > + MI.addOperand(MCOperand::CreateReg(getRegisterEnum(ARM::GPRRegClassID, > + decodeRn(insn)))); > + ++OpIdx; > + > + // For reg/reg form, base reg is followed by +/- reg. > + // For immediate form, it is followed by +/- imm8. > + // See also ARMAddressingModes.h (Addressing Mode #3). > + if (OpIdx + 1 >= NumOps) > + return false; > + > + assert((OpInfo[OpIdx].RegClass == ARM::GPRRegClassID) && > + (OpInfo[OpIdx+1].RegClass == 0)); > + > + ARM_AM::AddrOpc AddrOpcode = getUBit(insn) ? ARM_AM::add : ARM_AM::sub; > + if (getAM3IBit(insn) == 1) { > + MI.addOperand(MCOperand::CreateReg(0)); > + > + // Disassemble the 8-bit immediate offset. > + unsigned Imm4H = (insn >> ARMII::ImmHiShift) & 0xF; > + unsigned Imm4L = insn & 0xF; > + unsigned Offset = ARM_AM::getAM3Opc(AddrOpcode, (Imm4H << 4) | Imm4L); > + MI.addOperand(MCOperand::CreateImm(Offset)); > + } else { > + // Disassemble the offset reg (Rm). > + MI.addOperand(MCOperand::CreateReg(getRegisterEnum(ARM::GPRRegClassID, > + decodeRm(insn)))); > + unsigned Offset = ARM_AM::getAM3Opc(AddrOpcode, 0); > + MI.addOperand(MCOperand::CreateImm(Offset)); > + } > + OpIdx += 2; > + > + return true; > +} > + > +static bool DisassembleLdMiscFrm(MCInst &MI, unsigned Opcode, uint32_t insn, > + unsigned short NumOps, unsigned &NumOpsAdded) { > + return DisassembleLdStMiscFrm(MI, Opcode, insn, NumOps, NumOpsAdded, false); > +} > + > +static bool DisassembleStMiscFrm(MCInst &MI, unsigned Opcode, uint32_t insn, > + unsigned short NumOps, unsigned &NumOpsAdded) { > + return DisassembleLdStMiscFrm(MI, Opcode, insn, NumOps, NumOpsAdded, true); > +} > + > +// The algorithm for disassembly of LdStMulFrm is different from others because > +// it explicitly populates the two predicate operands after operand 0 (the base) > +// and operand 1 (the AM4 mode imm). After operand 3, we need to populate the > +// reglist with each affected register encoded as an MCOperand. > +static bool DisassembleLdStMulFrm(MCInst &MI, unsigned Opcode, uint32_t insn, > + unsigned short NumOps, unsigned &NumOpsAdded) { > + > + assert(NumOps == 5 && "LdStMulFrm expects NumOps of 5"); > + > + unsigned &OpIdx = NumOpsAdded; > + > + unsigned Base = getRegisterEnum(ARM::GPRRegClassID, decodeRn(insn)); > + MI.addOperand(MCOperand::CreateReg(Base)); > + > + ARM_AM::AMSubMode SubMode = getAMSubModeForBits(getPUBits(insn)); > + bool WB = getWBit(insn) == 1; > + MI.addOperand(MCOperand::CreateImm(ARM_AM::getAM4ModeImm(SubMode, WB))); > + > + // Handling the two predicate operands before the reglist. > + int64_t CondVal = insn >> ARMII::CondShift; > + MI.addOperand(MCOperand::CreateImm(CondVal == 0xF ? 0xE : CondVal)); > + MI.addOperand(MCOperand::CreateReg(ARM::CPSR)); > + > + OpIdx = 4; > + > + // Fill the variadic part of reglist. > + unsigned RegListBits = insn & ((1 << 16) - 1); > + for (unsigned i = 0; i < 16; ++i) { > + if ((RegListBits >> i) & 1) { > + MI.addOperand(MCOperand::CreateReg(getRegisterEnum(ARM::GPRRegClassID, > + i))); > + ++OpIdx; > + } > + } > + > + return true; > +} > + > +// LDREX, LDREXB, LDREXH: Rd Rn > +// LDREXD: Rd Rd+1 Rn > +// STREX, STREXB, STREXH: Rd Rm Rn > +// STREXD: Rd Rm Rm+1 Rn > +// > +// SWP, SWPB: Rd Rm Rn > +static bool DisassembleLdStExFrm(MCInst &MI, unsigned Opcode, uint32_t insn, > + unsigned short NumOps, unsigned &NumOpsAdded) { > + > + const TargetOperandInfo *OpInfo = ARMInsts[Opcode].OpInfo; > + unsigned &OpIdx = NumOpsAdded; > + > + OpIdx = 0; > + > + assert(NumOps >= 2 > + && OpInfo[0].RegClass == ARM::GPRRegClassID > + && OpInfo[1].RegClass == ARM::GPRRegClassID); > + > + bool isStore = slice(insn, 20, 20) == 0; > + bool isDW = (Opcode == ARM::LDREXD || Opcode == ARM::STREXD); > + > + // Add the destination operand. > + MI.addOperand(MCOperand::CreateReg(getRegisterEnum(ARM::GPRRegClassID, > + decodeRd(insn)))); > + ++OpIdx; > + > + // Store register Exclusive needs a source operand. > + if (isStore) { > + MI.addOperand(MCOperand::CreateReg(getRegisterEnum(ARM::GPRRegClassID, > + decodeRm(insn)))); > + ++OpIdx; > + > + if (isDW) { > + MI.addOperand(MCOperand::CreateReg(getRegisterEnum(ARM::GPRRegClassID, > + decodeRm(insn)+1))); > + ++OpIdx; > + } > + } else if (isDW) { > + MI.addOperand(MCOperand::CreateReg(getRegisterEnum(ARM::GPRRegClassID, > + decodeRd(insn)+1))); > + ++OpIdx; > + } > + > + // Finally add the pointer operand. > + MI.addOperand(MCOperand::CreateReg(getRegisterEnum(ARM::GPRRegClassID, > + decodeRn(insn)))); > + ++OpIdx; > + > + return true; > +} > + > +// Misc. Arithmetic Instructions. > +// CLZ: Rd Rm > +// PKHBT, PKHTB: Rd Rn Rm , LSL/ASR #imm5 > +// RBIT, REV, REV16, REVSH: Rd Rm > +static bool DisassembleArithMiscFrm(MCInst &MI, unsigned Opcode, uint32_t insn, > + unsigned short NumOps, unsigned &NumOpsAdded) { > + > + const TargetOperandInfo *OpInfo = ARMInsts[Opcode].OpInfo; > + unsigned &OpIdx = NumOpsAdded; > + > + OpIdx = 0; > + > + assert(NumOps >= 2 > + && OpInfo[0].RegClass == ARM::GPRRegClassID > + && OpInfo[1].RegClass == ARM::GPRRegClassID); > + > + bool ThreeReg = NumOps > 2 && OpInfo[2].RegClass == ARM::GPRRegClassID; > + > + MI.addOperand(MCOperand::CreateReg(getRegisterEnum(ARM::GPRRegClassID, > + decodeRd(insn)))); > + ++OpIdx; > + > + if (ThreeReg) { > + assert(NumOps >= 4); > + MI.addOperand(MCOperand::CreateReg(getRegisterEnum(ARM::GPRRegClassID, > + decodeRn(insn)))); > + ++OpIdx; > + } > + > + MI.addOperand(MCOperand::CreateReg(getRegisterEnum(ARM::GPRRegClassID, > + decodeRm(insn)))); > + ++OpIdx; > + > + // If there is still an operand info left which is an immediate operand, add > + // an additional imm5 LSL/ASR operand. > + if (ThreeReg && OpInfo[OpIdx].RegClass == 0 > + && !OpInfo[OpIdx].isPredicate() && !OpInfo[OpIdx].isOptionalDef()) { > + // Extract the 5-bit immediate field Inst{11-7}. > + unsigned ShiftAmt = (insn >> ARMII::ShiftShift) & 0x1F; > + MI.addOperand(MCOperand::CreateImm(ShiftAmt)); > + ++OpIdx; > + } > + > + return true; > +} > + > +// Extend instructions. > +// SXT* and UXT*: Rd [Rn] Rm [rot_imm]. > +// The 2nd operand register is Rn and the 3rd operand regsiter is Rm for the > +// three register operand form. Otherwise, Rn=0b1111 and only Rm is used. > +static bool DisassembleExtFrm(MCInst &MI, unsigned Opcode, uint32_t insn, > + unsigned short NumOps, unsigned &NumOpsAdded) { > + > + const TargetOperandInfo *OpInfo = ARMInsts[Opcode].OpInfo; > + unsigned &OpIdx = NumOpsAdded; > + > + OpIdx = 0; > + > + assert(NumOps >= 2 > + && OpInfo[0].RegClass == ARM::GPRRegClassID > + && OpInfo[1].RegClass == ARM::GPRRegClassID); > + > + bool ThreeReg = NumOps > 2 && OpInfo[2].RegClass == ARM::GPRRegClassID; > + > + MI.addOperand(MCOperand::CreateReg(getRegisterEnum(ARM::GPRRegClassID, > + decodeRd(insn)))); > + ++OpIdx; > + > + if (ThreeReg) { > + MI.addOperand(MCOperand::CreateReg(getRegisterEnum(ARM::GPRRegClassID, > + decodeRn(insn)))); > + ++OpIdx; > + } > + > + MI.addOperand(MCOperand::CreateReg(getRegisterEnum(ARM::GPRRegClassID, > + decodeRm(insn)))); > + ++OpIdx; > + > + // If there is still an operand info left which is an immediate operand, add > + // an additional rotate immediate operand. > + if (OpIdx < NumOps && OpInfo[OpIdx].RegClass == 0 > + && !OpInfo[OpIdx].isPredicate() && !OpInfo[OpIdx].isOptionalDef()) { > + // Extract the 2-bit rotate field Inst{11-10}. > + unsigned rot = (insn >> ARMII::ExtRotImmShift) & 3; > + // Rotation by 8, 16, or 24 bits. > + MI.addOperand(MCOperand::CreateImm(rot << 3)); > + ++OpIdx; > + } > + > + return true; > +} > + > +///////////////////////////////////// > +// // > +// Utility Functions For VFP // > +// // > +///////////////////////////////////// > + > +// Extract/Decode Dd/Sd: > +// > +// SP => d = UInt(Vd:D) > +// DP => d = UInt(D:Vd) > +static unsigned decodeVFPRd(uint32_t insn, bool isSPVFP) { > + return isSPVFP ? (decodeRd(insn) << 1 | getDBit(insn)) > + : (decodeRd(insn) | getDBit(insn) << 4); > +} > + > +// Extract/Decode Dn/Sn: > +// > +// SP => n = UInt(Vn:N) > +// DP => n = UInt(N:Vn) > +static unsigned decodeVFPRn(uint32_t insn, bool isSPVFP) { > + return isSPVFP ? (decodeRn(insn) << 1 | getNBit(insn)) > + : (decodeRn(insn) | getNBit(insn) << 4); > +} > + > +// Extract/Decode Dm/Sm: > +// > +// SP => m = UInt(Vm:M) > +// DP => m = UInt(M:Vm) > +static unsigned decodeVFPRm(uint32_t insn, bool isSPVFP) { > + return isSPVFP ? (decodeRm(insn) << 1 | getMBit(insn)) > + : (decodeRm(insn) | getMBit(insn) << 4); > +} > + > +// A7.5.1 > +#if 0 > +static uint64_t VFPExpandImm(unsigned char byte, unsigned N) { > + assert(N == 32 || N == 64); > + > + uint64_t Result; > + unsigned bit6 = slice(byte, 6, 6); > + if (N == 32) { > + Result = slice(byte, 7, 7) << 31 | slice(byte, 5, 0) << 19; > + if (bit6) > + Result |= 0x1f << 25; > + else > + Result |= 0x1 << 30; > + } else { > + Result = (uint64_t)slice(byte, 7, 7) << 63 | > + (uint64_t)slice(byte, 5, 0) << 48; > + if (bit6) > + Result |= 0xffL << 54; > + else > + Result |= 0x1L << 62; > + } > + return Result; > +} > +#endif > + > +// VFP Unary Format Instructions: > +// > +// VCMP[E]ZD, VCMP[E]ZS: compares one floating-point register with zero > +// VCVTDS, VCVTSD: converts between double-precision and single-precision > +// The rest of the instructions have homogeneous [VFP]Rd and [VFP]Rm registers. > +static bool DisassembleVFPUnaryFrm(MCInst &MI, unsigned Opcode, uint32_t insn, > + unsigned short NumOps, unsigned &NumOpsAdded) { > + > + assert(NumOps >= 1 && "VFPUnaryFrm expects NumOps >= 1"); > + > + const TargetOperandInfo *OpInfo = ARMInsts[Opcode].OpInfo; > + unsigned &OpIdx = NumOpsAdded; > + > + OpIdx = 0; > + > + unsigned RegClass = OpInfo[OpIdx].RegClass; > + assert(RegClass == ARM::SPRRegClassID || RegClass == ARM::DPRRegClassID); > + bool isSP = (RegClass == ARM::SPRRegClassID); > + > + MI.addOperand(MCOperand::CreateReg( > + getRegisterEnum(RegClass, decodeVFPRd(insn, isSP)))); > + ++OpIdx; > + > + // Early return for compare with zero instructions. > + if (Opcode == ARM::VCMPEZD || Opcode == ARM::VCMPEZS > + || Opcode == ARM::VCMPZD || Opcode == ARM::VCMPZS) > + return true; > + > + RegClass = OpInfo[OpIdx].RegClass; > + assert(RegClass == ARM::SPRRegClassID || RegClass == ARM::DPRRegClassID); > + isSP = (RegClass == ARM::SPRRegClassID); > + > + MI.addOperand(MCOperand::CreateReg( > + getRegisterEnum(RegClass, decodeVFPRm(insn, isSP)))); > + ++OpIdx; > + > + return true; > +} > + > +// All the instructions have homogeneous [VFP]Rd, [VFP]Rn, and [VFP]Rm regs. > +// Some of them have operand constraints which tie the first operand in the > +// InOperandList to that of the dst. As far as asm printing is concerned, this > +// tied_to operand is simply skipped. > +static bool DisassembleVFPBinaryFrm(MCInst &MI, unsigned Opcode, uint32_t insn, > + unsigned short NumOps, unsigned &NumOpsAdded) { > + > + assert(NumOps >= 3 && "VFPBinaryFrm expects NumOps >= 3"); > + > + const TargetInstrDesc &TID = ARMInsts[Opcode]; > + const TargetOperandInfo *OpInfo = TID.OpInfo; > + unsigned &OpIdx = NumOpsAdded; > + > + OpIdx = 0; > + > + unsigned RegClass = OpInfo[OpIdx].RegClass; > + assert(RegClass == ARM::SPRRegClassID || RegClass == ARM::DPRRegClassID); > + bool isSP = (RegClass == ARM::SPRRegClassID); > + > + MI.addOperand(MCOperand::CreateReg( > + getRegisterEnum(RegClass, decodeVFPRd(insn, isSP)))); > + ++OpIdx; > + > + // Skip tied_to operand constraint. > + if (TID.getOperandConstraint(OpIdx, TOI::TIED_TO) != -1) { > + assert(NumOps >= 4); > + MI.addOperand(MCOperand::CreateReg(0)); > + ++OpIdx; > + } > + > + MI.addOperand(MCOperand::CreateReg( > + getRegisterEnum(RegClass, decodeVFPRn(insn, isSP)))); > + ++OpIdx; > + > + MI.addOperand(MCOperand::CreateReg( > + getRegisterEnum(RegClass, decodeVFPRm(insn, isSP)))); > + ++OpIdx; > + > + return true; > +} > + > +// A8.6.295 vcvt (floating-point <-> integer) > +// Int to FP: VSITOD, VSITOS, VUITOD, VUITOS > +// FP to Int: VTOSI[Z|R]D, VTOSI[Z|R]S, VTOUI[Z|R]D, VTOUI[Z|R]S > +// > +// A8.6.297 vcvt (floating-point and fixed-point) > +// Dd|Sd Dd|Sd(TIED_TO) #fbits(= 16|32 - UInt(imm4:i)) > +static bool DisassembleVFPConv1Frm(MCInst &MI, unsigned Opcode, uint32_t insn, > + unsigned short NumOps, unsigned &NumOpsAdded) { > + > + assert(NumOps >= 2 && "VFPConv1Frm expects NumOps >= 2"); > + > + const TargetInstrDesc &TID = ARMInsts[Opcode]; > + const TargetOperandInfo *OpInfo = TID.OpInfo; > + > + bool SP = slice(insn, 8, 8) == 0; // A8.6.295 & A8.6.297 > + bool fixed_point = slice(insn, 17, 17) == 1; // A8.6.297 > + unsigned RegClassID = SP ? ARM::SPRRegClassID : ARM::DPRRegClassID; > + > + if (fixed_point) { > + // A8.6.297 > + assert(NumOps >= 3); > + int size = slice(insn, 7, 7) == 0 ? 16 : 32; > + int fbits = size - (slice(insn,3,0) << 1 | slice(insn,5,5)); > + MI.addOperand(MCOperand::CreateReg( > + getRegisterEnum(RegClassID, > + decodeVFPRd(insn, SP)))); > + > + assert(TID.getOperandConstraint(1, TOI::TIED_TO) != -1); > + MI.addOperand(MI.getOperand(0)); > + > + assert(OpInfo[2].RegClass == 0 && !OpInfo[2].isPredicate() && > + !OpInfo[2].isOptionalDef()); > + MI.addOperand(MCOperand::CreateImm(fbits)); > + > + NumOpsAdded = 3; > + } else { > + // A8.6.295 > + // The Rd (destination) and Rm (source) bits have different interpretations > + // depending on their single-precisonness. > + unsigned d, m; > + if (slice(insn, 18, 18) == 1) { // to_integer operation > + d = decodeVFPRd(insn, true /* Is Single Precision */); > + MI.addOperand(MCOperand::CreateReg( > + getRegisterEnum(ARM::SPRRegClassID, d))); > + m = decodeVFPRm(insn, SP); > + MI.addOperand(MCOperand::CreateReg(getRegisterEnum(RegClassID, m))); > + } else { > + d = decodeVFPRd(insn, SP); > + MI.addOperand(MCOperand::CreateReg(getRegisterEnum(RegClassID, d))); > + m = decodeVFPRm(insn, true /* Is Single Precision */); > + MI.addOperand(MCOperand::CreateReg( > + getRegisterEnum(ARM::SPRRegClassID, m))); > + } > + NumOpsAdded = 2; > + } > + > + return true; > +} > + > +// VMOVRS - A8.6.330 > +// Rt => Rd; Sn => UInt(Vn:N) > +static bool DisassembleVFPConv2Frm(MCInst &MI, unsigned Opcode, uint32_t insn, > + unsigned short NumOps, unsigned &NumOpsAdded) { > + > + assert(NumOps >= 2 && "VFPConv2Frm expects NumOps >= 2"); > + > + MI.addOperand(MCOperand::CreateReg(getRegisterEnum(ARM::GPRRegClassID, > + decodeRd(insn)))); > + MI.addOperand(MCOperand::CreateReg(getRegisterEnum(ARM::SPRRegClassID, > + decodeVFPRn(insn, true)))); > + NumOpsAdded = 2; > + return true; > +} > + > +// VMOVRRD - A8.6.332 > +// Rt => Rd; Rt2 => Rn; Dm => UInt(M:Vm) > +// > +// VMOVRRS - A8.6.331 > +// Rt => Rd; Rt2 => Rn; Sm => UInt(Vm:M); Sm1 = Sm+1 > +static bool DisassembleVFPConv3Frm(MCInst &MI, unsigned Opcode, uint32_t insn, > + unsigned short NumOps, unsigned &NumOpsAdded) { > + > + assert(NumOps >= 3 && "VFPConv3Frm expects NumOps >= 3"); > + > + const TargetOperandInfo *OpInfo = ARMInsts[Opcode].OpInfo; > + unsigned &OpIdx = NumOpsAdded; > + > + MI.addOperand(MCOperand::CreateReg(getRegisterEnum(ARM::GPRRegClassID, > + decodeRd(insn)))); > + MI.addOperand(MCOperand::CreateReg(getRegisterEnum(ARM::GPRRegClassID, > + decodeRn(insn)))); > + OpIdx = 2; > + > + if (OpInfo[OpIdx].RegClass == ARM::SPRRegClassID) { > + unsigned Sm = decodeVFPRm(insn, true); > + MI.addOperand(MCOperand::CreateReg(getRegisterEnum(ARM::SPRRegClassID, > + Sm))); > + MI.addOperand(MCOperand::CreateReg(getRegisterEnum(ARM::SPRRegClassID, > + Sm+1))); > + OpIdx += 2; > + } else { > + MI.addOperand(MCOperand::CreateReg( > + getRegisterEnum(ARM::DPRRegClassID, > + decodeVFPRm(insn, false)))); > + ++OpIdx; > + } > + return true; > +} > + > +// VMOVSR - A8.6.330 > +// Rt => Rd; Sn => UInt(Vn:N) > +static bool DisassembleVFPConv4Frm(MCInst &MI, unsigned Opcode, uint32_t insn, > + unsigned short NumOps, unsigned &NumOpsAdded) { > + > + assert(NumOps >= 2 && "VFPConv4Frm expects NumOps >= 2"); > + > + MI.addOperand(MCOperand::CreateReg(getRegisterEnum(ARM::SPRRegClassID, > + decodeVFPRn(insn, true)))); > + MI.addOperand(MCOperand::CreateReg(getRegisterEnum(ARM::GPRRegClassID, > + decodeRd(insn)))); > + NumOpsAdded = 2; > + return true; > +} > + > +// VMOVDRR - A8.6.332 > +// Rt => Rd; Rt2 => Rn; Dm => UInt(M:Vm) > +// > +// VMOVRRS - A8.6.331 > +// Rt => Rd; Rt2 => Rn; Sm => UInt(Vm:M); Sm1 = Sm+1 > +static bool DisassembleVFPConv5Frm(MCInst &MI, unsigned Opcode, uint32_t insn, > + unsigned short NumOps, unsigned &NumOpsAdded) { > + > + assert(NumOps >= 3 && "VFPConv5Frm expects NumOps >= 3"); > + > + const TargetOperandInfo *OpInfo = ARMInsts[Opcode].OpInfo; > + unsigned &OpIdx = NumOpsAdded; > + > + OpIdx = 0; > + > + if (OpInfo[OpIdx].RegClass == ARM::SPRRegClassID) { > + unsigned Sm = decodeVFPRm(insn, true); > + MI.addOperand(MCOperand::CreateReg(getRegisterEnum(ARM::SPRRegClassID, > + Sm))); > + MI.addOperand(MCOperand::CreateReg(getRegisterEnum(ARM::SPRRegClassID, > + Sm+1))); > + OpIdx += 2; > + } else { > + MI.addOperand(MCOperand::CreateReg( > + getRegisterEnum(ARM::DPRRegClassID, > + decodeVFPRm(insn, false)))); > + ++OpIdx; > + } > + > + MI.addOperand(MCOperand::CreateReg(getRegisterEnum(ARM::GPRRegClassID, > + decodeRd(insn)))); > + MI.addOperand(MCOperand::CreateReg(getRegisterEnum(ARM::GPRRegClassID, > + decodeRn(insn)))); > + OpIdx += 2; > + return true; > +} > + > +// VFP Load/Store Instructions. > +// VLDRD, VLDRS, VSTRD, VSTRS > +static bool DisassembleVFPLdStFrm(MCInst &MI, unsigned Opcode, uint32_t insn, > + unsigned short NumOps, unsigned &NumOpsAdded) { > + > + assert(NumOps >= 3 && "VFPLdStFrm expects NumOps >= 3"); > + > + bool isSPVFP = (Opcode == ARM::VLDRS || Opcode == ARM::VSTRS) ? true : false; > + unsigned RegClassID = isSPVFP ? ARM::SPRRegClassID : ARM::DPRRegClassID; > + > + // Extract Dd/Sd for operand 0. > + unsigned RegD = decodeVFPRd(insn, isSPVFP); > + > + MI.addOperand(MCOperand::CreateReg(getRegisterEnum(RegClassID, RegD))); > + > + unsigned Base = getRegisterEnum(ARM::GPRRegClassID, decodeRn(insn)); > + MI.addOperand(MCOperand::CreateReg(Base)); > + > + // Next comes the AM5 Opcode. > + ARM_AM::AddrOpc AddrOpcode = getUBit(insn) ? ARM_AM::add : ARM_AM::sub; > + unsigned char Imm8 = insn & 0xFF; > + MI.addOperand(MCOperand::CreateImm(ARM_AM::getAM5Opc(AddrOpcode, Imm8))); > + > + NumOpsAdded = 3; > + > + return true; > +} > + > +// VFP Load/Store Multiple Instructions. > +// This is similar to the algorithm for LDM/STM in that operand 0 (the base) and > +// operand 1 (the AM5 mode imm) is followed by two predicate operands. It is > +// followed by a reglist of either DPR(s) or SPR(s). > +// > +// VLDMD, VLDMS, VSTMD, VSTMS > +static bool DisassembleVFPLdStMulFrm(MCInst &MI, unsigned Opcode, uint32_t insn, > + unsigned short NumOps, unsigned &NumOpsAdded) { > + > + assert(NumOps == 5 && "VFPLdStMulFrm expects NumOps of 5"); > + > + unsigned &OpIdx = NumOpsAdded; > + > + unsigned Base = getRegisterEnum(ARM::GPRRegClassID, decodeRn(insn)); > + MI.addOperand(MCOperand::CreateReg(Base)); > + > + // Next comes the AM5 Opcode. > + ARM_AM::AMSubMode SubMode = getAMSubModeForBits(getPUBits(insn)); > + bool WB = getWBit(insn) == 1; > + unsigned char Imm8 = insn & 0xFF; > + MI.addOperand(MCOperand::CreateImm(ARM_AM::getAM5Opc(SubMode, WB, Imm8))); > + > + // Handling the two predicate operands before the reglist. > + int64_t CondVal = insn >> ARMII::CondShift; > + MI.addOperand(MCOperand::CreateImm(CondVal == 0xF ? 0xE : CondVal)); > + MI.addOperand(MCOperand::CreateReg(ARM::CPSR)); > + > + OpIdx = 4; > + > + bool isSPVFP = (Opcode == ARM::VLDMS || Opcode == ARM::VSTMS) ? true : false; > + unsigned RegClassID = isSPVFP ? ARM::SPRRegClassID : ARM::DPRRegClassID; > + > + // Extract Dd/Sd. > + unsigned RegD = decodeVFPRd(insn, isSPVFP); > + > + // Fill the variadic part of reglist. > + unsigned Regs = isSPVFP ? Imm8 : Imm8/2; > + for (unsigned i = 0; i < Regs; ++i) { > + MI.addOperand(MCOperand::CreateReg(getRegisterEnum(RegClassID, > + RegD + i))); > + ++OpIdx; > + } > + > + return true; > +} > + > +// Misc. VFP Instructions. > +// FMSTAT (vmrs with Rt=0b1111, i.e., to apsr_nzcv and no register operand) > +// FCONSTD (DPR and a VFPf64Imm operand) > +// FCONSTS (SPR and a VFPf32Imm operand) > +// VMRS/VMSR (GPR operand) > +static bool DisassembleVFPMiscFrm(MCInst &MI, unsigned Opcode, uint32_t insn, > + unsigned short NumOps, unsigned &NumOpsAdded) { > + > + const TargetOperandInfo *OpInfo = ARMInsts[Opcode].OpInfo; > + unsigned &OpIdx = NumOpsAdded; > + > + OpIdx = 0; > + > + if (Opcode == ARM::FMSTAT) > + return true; > + > + assert(NumOps >= 2); > + > + unsigned RegEnum = 0; > + switch (OpInfo[0].RegClass) { > + case ARM::DPRRegClassID: > + RegEnum = getRegisterEnum(ARM::DPRRegClassID, decodeVFPRd(insn, false)); > + break; > + case ARM::SPRRegClassID: > + RegEnum = getRegisterEnum(ARM::SPRRegClassID, decodeVFPRd(insn, true)); > + break; > + case ARM::GPRRegClassID: > + RegEnum = getRegisterEnum(ARM::GPRRegClassID, decodeRd(insn)); > + break; > + default: > + llvm_unreachable("Invalid reg class id"); > + } > + > + MI.addOperand(MCOperand::CreateReg(RegEnum)); > + ++OpIdx; > + > + // Extract/decode the f64/f32 immediate. > + if (OpIdx < NumOps && OpInfo[OpIdx].RegClass == 0 > + && !OpInfo[OpIdx].isPredicate() && !OpInfo[OpIdx].isOptionalDef()) { > + // The asm syntax specifies the before-expanded . > + // Not VFPExpandImm(slice(insn,19,16) << 4 | slice(insn, 3, 0), > + // Opcode == ARM::FCONSTD ? 64 : 32) > + MI.addOperand(MCOperand::CreateImm(slice(insn,19,16)<<4 | slice(insn,3,0))); > + ++OpIdx; > + } > + > + return true; > +} > + > +// DisassembleThumbFrm() is defined in ThumbDisassemblerCore.cpp.inc file. > +#include "ThumbDisassemblerCore.cpp.inc" > + > +///////////////////////////////////////////////////// > +// // > +// Utility Functions For ARM Advanced SIMD // > +// // > +///////////////////////////////////////////////////// > + > +// The following NEON namings are based on A8.6.266 VABA, VABAL. Notice that > +// A8.6.303 VDUP (ARM core register)'s D/Vd pair is the N/Vn pair of VABA/VABAL. > + > +// A7.3 Register encoding > + > +// Extract/Decode NEON D/Vd: > +// > +// Note that for quadword, Qd = UInt(D:Vd<3:1>) = Inst{22:15-13}, whereas for > +// doubleword, Dd = UInt(D:Vd). We compensate for this difference by > +// handling it in the getRegisterEnum() utility function. > +// D = Inst{22}, Vd = Inst{15-12} > +static unsigned decodeNEONRd(uint32_t insn) { > + return ((insn >> ARMII::NEON_D_BitShift) & 1) << 4 > + | (insn >> ARMII::NEON_RegRdShift) & ARMII::NEONRegMask; > +} > + > +// Extract/Decode NEON N/Vn: > +// > +// Note that for quadword, Qn = UInt(N:Vn<3:1>) = Inst{7:19-17}, whereas for > +// doubleword, Dn = UInt(N:Vn). We compensate for this difference by > +// handling it in the getRegisterEnum() utility function. > +// N = Inst{7}, Vn = Inst{19-16} > +static unsigned decodeNEONRn(uint32_t insn) { > + return ((insn >> ARMII::NEON_N_BitShift) & 1) << 4 > + | (insn >> ARMII::NEON_RegRnShift) & ARMII::NEONRegMask; > +} > + > +// Extract/Decode NEON M/Vm: > +// > +// Note that for quadword, Qm = UInt(M:Vm<3:1>) = Inst{5:3-1}, whereas for > +// doubleword, Dm = UInt(M:Vm). We compensate for this difference by > +// handling it in the getRegisterEnum() utility function. > +// M = Inst{5}, Vm = Inst{3-0} > +static unsigned decodeNEONRm(uint32_t insn) { > + return ((insn >> ARMII::NEON_M_BitShift) & 1) << 4 > + | (insn >> ARMII::NEON_RegRmShift) & ARMII::NEONRegMask; > +} > + > +namespace { > +enum ElemSize { > + ESizeNA = 0, > + ESize8 = 8, > + ESize16 = 16, > + ESize32 = 32, > + ESize64 = 64 > +}; > +} // End of unnamed namespace > + > +// size field -> Inst{11-10} > +// index_align field -> Inst{7-4} > +// > +// The Lane Index interpretation depends on the Data Size: > +// 8 (encoded as size = 0b00) -> Index = index_align[3:1] > +// 16 (encoded as size = 0b01) -> Index = index_align[3:2] > +// 32 (encoded as size = 0b10) -> Index = index_align[3] > +// > +// Ref: A8.6.317 VLD4 (single 4-element structure to one lane). > +static unsigned decodeLaneIndex(uint32_t insn) { > + unsigned size = insn >> 10 & 3; > + assert(size == 0 || size == 1 || size == 2); > + > + unsigned index_align = insn >> 4 & 0xF; > + return (index_align >> 1) >> size; > +} > + > +// imm64 = AdvSIMDExpandImm(op, cmode, i:imm3:imm4) > +// op = Inst{5}, cmode = Inst{11-8} > +// i = Inst{24} (ARM architecture) > +// imm3 = Inst{18-16}, imm4 = Inst{3-0} > +// Ref: Table A7-15 Modified immediate values for Advanced SIMD instructions. > +static uint64_t decodeN1VImm(uint32_t insn, ElemSize esize) { > + unsigned char cmode = (insn >> 8) & 0xF; > + unsigned char Imm8 = ((insn >> 24) & 1) << 7 | > + ((insn >> 16) & 7) << 4 | > + (insn & 0xF); > + uint64_t Imm64 = 0; > + > + switch (esize) { > + case ESize8: > + Imm64 = Imm8; > + break; > + case ESize16: > + Imm64 = Imm8 << 8*(cmode >> 1 & 1); > + break; > + case ESize32: { > + if (cmode == 12) > + Imm64 = (Imm8 << 8) | 0xFF; > + else if (cmode == 13) > + Imm64 = (Imm8 << 16) | 0xFFFF; > + else { > + // Imm8 to be shifted left by how many bytes... > + Imm64 = Imm8 << 8*(cmode >> 1 & 3); > + } > + break; > + } > + case ESize64: { > + for (unsigned i = 0; i < 8; ++i) > + if ((Imm8 >> i) & 1) > + Imm64 |= 0xFF << 8*i; > + break; > + } > + default: > + assert(0 && "Unreachable code!"); > + return 0; > + } > + > + return Imm64; > +} > + > +// A8.6.339 VMUL, VMULL (by scalar) > +// ESize16 => m = Inst{2-0} (Vm<2:0>) D0-D7 > +// ESize32 => m = Inst{3-0} (Vm<3:0>) D0-D15 > +static unsigned decodeRestrictedDm(uint32_t insn, ElemSize esize) { > + switch (esize) { > + case ESize16: > + return insn & 7; > + case ESize32: > + return insn & 0xF; > + default: > + assert(0 && "Unreachable code!"); > + return 0; > + } > +} > + > +// A8.6.339 VMUL, VMULL (by scalar) > +// ESize16 => index = Inst{5:3} (M:Vm<3>) D0-D7 > +// ESize32 => index = Inst{5} (M) D0-D15 > +static unsigned decodeRestrictedDmIndex(uint32_t insn, ElemSize esize) { > + switch (esize) { > + case ESize16: > + return (((insn >> 5) & 1) << 1) | ((insn >> 3) & 1); > + case ESize32: > + return (insn >> 5) & 1; > + default: > + assert(0 && "Unreachable code!"); > + return 0; > + } > +} > + > +// A8.6.296 VCVT (between floating-point and fixed-point, Advanced SIMD) > +// (64 - ) is encoded as imm6, i.e., Inst{21-16}. > +static unsigned decodeVCVTFractionBits(uint32_t insn) { > + return 64 - ((insn >> 16) & 0x3F); > +} > + > +// A8.6.302 VDUP (scalar) > +// ESize8 => index = Inst{19-17} > +// ESize16 => index = Inst{19-18} > +// ESize32 => index = Inst{19} > +static unsigned decodeNVLaneDupIndex(uint32_t insn, ElemSize esize) { > + switch (esize) { > + case ESize8: > + return (insn >> 17) & 7; > + case ESize16: > + return (insn >> 18) & 3; > + case ESize32: > + return (insn >> 19) & 1; > + default: > + assert(0 && "Unspecified element size!"); > + return 0; > + } > +} > + > +// A8.6.328 VMOV (ARM core register to scalar) > +// A8.6.329 VMOV (scalar to ARM core register) > +// ESize8 => index = Inst{21:6-5} > +// ESize16 => index = Inst{21:6} > +// ESize32 => index = Inst{21} > +static unsigned decodeNVLaneOpIndex(uint32_t insn, ElemSize esize) { > + switch (esize) { > + case ESize8: > + return ((insn >> 21) & 1) << 2 | ((insn >> 5) & 3); > + case ESize16: > + return ((insn >> 21) & 1) << 1 | ((insn >> 6) & 1); > + case ESize32: > + return ((insn >> 21) & 1); > + default: > + assert(0 && "Unspecified element size!"); > + return 0; > + } > +} > + > +// Imm6 = Inst{21-16}, L = Inst{7} > +// > +// NormalShift == true (A8.6.376 VRSHR, A8.6.368 VQSHRN): > +// case L:imm6 of > +// '0001xxx' => esize = 8; shift_amount = 16 - imm6 > +// '001xxxx' => esize = 16; shift_amount = 32 - imm6 > +// '01xxxxx' => esize = 32; shift_amount = 64 - imm6 > +// '1xxxxxx' => esize = 64; shift_amount = 64 - imm6 > +// > +// NormalShift == false (A8.6.367 VQSHL, A8.6.387 VSLI): > +// case L:imm6 of > +// '0001xxx' => esize = 8; shift_amount = imm6 - 8 > +// '001xxxx' => esize = 16; shift_amount = imm6 - 16 > +// '01xxxxx' => esize = 32; shift_amount = imm6 - 32 > +// '1xxxxxx' => esize = 64; shift_amount = imm6 > +// > +static unsigned decodeNVSAmt(uint32_t insn, bool NormalShift) { > + ElemSize esize = ESizeNA; > + unsigned L = (insn >> 7) & 1; > + unsigned imm6 = (insn >> 16) & 0x3F; > + if (L == 0) { > + if (imm6 >> 3 == 1) > + esize = ESize8; > + else if (imm6 >> 4 == 1) > + esize = ESize16; > + else if (imm6 >> 5 == 1) > + esize = ESize32; > + else > + assert(0 && "Wrong encoding of Inst{7:21-16}!"); > + } else > + esize = ESize64; > + > + if (NormalShift) > + return esize == ESize64 ? (esize - imm6) : (2*esize - imm6); > + else > + return esize == ESize64 ? imm6 : (imm6 - esize); > +} > + > +// A8.6.305 VEXT > +// Imm4 = Inst{11-8} > +static unsigned decodeN3VImm(uint32_t insn) { > + return (insn >> 8) & 0xF; > +} > + > +static bool DisassembleNSFormatNone(MCInst &MI, unsigned Opcode, uint32_t insn, > + unsigned short NumOps, unsigned &NumOpsAdded) { > + assert(0 && "Unexpected NEON Sub-Format of NSFormatNone"); > + return false; > +} > + > +// VLD* > +// D[d] D[d2] ... R[addr] [TIED_TO] R[update] AM6 align(ignored) > +// VLD*LN* > +// D[d] D[d2] ... R[addr] R[update] AM6 align(ignored) TIED_TO ... imm(idx) > +// VST* > +// R[addr] [TIED_TO] R[update] AM6 align(ignored) D[d] D[d2] ... > +// VST*LN* > +// R[addr] R[update] AM6 align(ignored) D[d] D[d2] ... [imm(idx)] > +// > +// Correctly set VLD*/VST*'s TIED_TO GPR, as the asm printer needs it. > +static bool DisassembleVLDSTLane0(MCInst &MI, unsigned Opcode, uint32_t insn, > + unsigned short NumOps, unsigned &NumOpsAdded, bool Store, bool DblSpaced) { > + > + const TargetInstrDesc &TID = ARMInsts[Opcode]; > + const TargetOperandInfo *OpInfo = TID.OpInfo; > + > + // At least one DPR register plus addressing mode #6. > + assert(NumOps >= 5); > + > + unsigned &OpIdx = NumOpsAdded; > + > + OpIdx = 0; > + > + // We have homogeneous NEON registers for Load/Store. > + unsigned RegClass = 0; > + > + // Double-spaced registers have increments of 2. > + unsigned Inc = DblSpaced ? 2 : 1; > + > + unsigned Rn = decodeRn(insn); > + unsigned Rm = decodeRm(insn); > + unsigned Rd = decodeNEONRd(insn); > + > + // A7.7.1 Advanced SIMD addressing mode. > + bool WB = Rm != 15; > + > + // LLVM Addressing Mode #6. > + unsigned RmEnum = 0; > + if (WB && Rm != 13) > + RmEnum = getRegisterEnum(ARM::GPRRegClassID, Rm); > + > + if (Store) { > + // Consume AddrMode6 (possible TIED_TO Rn), the DPR/QPR's, then possible > + // lane index. > + assert(OpIdx < NumOps && OpInfo[0].RegClass == ARM::GPRRegClassID); > + MI.addOperand(MCOperand::CreateReg(getRegisterEnum(ARM::GPRRegClassID, > + Rn))); > + ++OpIdx; > + if (TID.getOperandConstraint(OpIdx, TOI::TIED_TO) != -1) { > + // TIED_TO operand. > + MI.addOperand(MCOperand::CreateReg(getRegisterEnum(ARM::GPRRegClassID, > + Rn))); > + ++OpIdx; > + } > + > + assert(OpIdx < NumOps && OpInfo[OpIdx].RegClass == ARM::GPRRegClassID); > + MI.addOperand(MCOperand::CreateReg(RmEnum)); > + ++OpIdx; > + assert(OpIdx < NumOps && > + OpInfo[OpIdx].RegClass == 0 && OpInfo[OpIdx+1].RegClass == 0); > + MI.addOperand(MCOperand::CreateImm(ARM_AM::getAM6Opc(WB))); > + MI.addOperand(MCOperand::CreateImm(0)); // Alignment ignored? > + OpIdx += 2; > + > + assert(OpIdx < NumOps && > + (OpInfo[OpIdx].RegClass == ARM::DPRRegClassID || > + OpInfo[OpIdx].RegClass == ARM::QPRRegClassID)); > + > + RegClass = OpInfo[OpIdx].RegClass; > + while (OpIdx < NumOps && OpInfo[OpIdx].RegClass == RegClass) { > + if (Opcode >= ARM::VST1q16 && Opcode <= ARM::VST1q8) > + MI.addOperand(MCOperand::CreateReg(getRegisterEnum(RegClass,Rd,true))); > + else > + MI.addOperand(MCOperand::CreateReg(getRegisterEnum(RegClass,Rd))); > + Rd += Inc; > + ++OpIdx; > + } > + > + // Handle possible lane index. > + if (OpIdx < NumOps && OpInfo[OpIdx].RegClass == 0 > + && !OpInfo[OpIdx].isPredicate() && !OpInfo[OpIdx].isOptionalDef()) { > + MI.addOperand(MCOperand::CreateImm(decodeLaneIndex(insn))); > + ++OpIdx; > + } > + > + } else { > + // Consume the DPR/QPR's, AddrMode6 (possible TIED_TO Rn), possible TIED_TO > + // DPR/QPR's (ignored), then possible lane index. > + RegClass = OpInfo[0].RegClass; > + > + while (OpIdx < NumOps && OpInfo[OpIdx].RegClass == RegClass) { > + if (Opcode >= ARM::VLD1q16 && Opcode <= ARM::VLD1q8) > + MI.addOperand(MCOperand::CreateReg(getRegisterEnum(RegClass,Rd,true))); > + else > + MI.addOperand(MCOperand::CreateReg(getRegisterEnum(RegClass,Rd))); > + Rd += Inc; > + ++OpIdx; > + } > + > + assert(OpIdx < NumOps && OpInfo[OpIdx].RegClass == ARM::GPRRegClassID); > + MI.addOperand(MCOperand::CreateReg(getRegisterEnum(ARM::GPRRegClassID, > + Rn))); > + ++OpIdx; > + if (TID.getOperandConstraint(OpIdx, TOI::TIED_TO) != -1) { > + // TIED_TO operand. > + MI.addOperand(MCOperand::CreateReg(getRegisterEnum(ARM::GPRRegClassID, > + Rn))); > + ++OpIdx; > + } > + > + assert(OpIdx < NumOps && OpInfo[OpIdx].RegClass == ARM::GPRRegClassID); > + MI.addOperand(MCOperand::CreateReg(RmEnum)); > + ++OpIdx; > + assert(OpIdx < NumOps && > + OpInfo[OpIdx].RegClass == 0 && OpInfo[OpIdx+1].RegClass == 0); > + MI.addOperand(MCOperand::CreateImm(ARM_AM::getAM6Opc(WB))); > + MI.addOperand(MCOperand::CreateImm(0)); // Alignment ignored? > + OpIdx += 2; > + > + while (OpIdx < NumOps && OpInfo[OpIdx].RegClass == RegClass) { > + assert(TID.getOperandConstraint(OpIdx, TOI::TIED_TO) != -1); > + MI.addOperand(MCOperand::CreateReg(0)); > + ++OpIdx; > + } > + > + // Handle possible lane index. > + if (OpIdx < NumOps && OpInfo[OpIdx].RegClass == 0 > + && !OpInfo[OpIdx].isPredicate() && !OpInfo[OpIdx].isOptionalDef()) { > + MI.addOperand(MCOperand::CreateImm(decodeLaneIndex(insn))); > + ++OpIdx; > + } > + } > + > + return true; > +} > + > +// A7.7 > +// If L (Inst{21}) == 0, store instructions. > +// DblSpaced = false. > +static bool DisassembleVLDSTLane(MCInst &MI, unsigned Opcode, uint32_t insn, > + unsigned short NumOps, unsigned &NumOpsAdded) { > + > + return DisassembleVLDSTLane0(MI, Opcode, insn, NumOps, NumOpsAdded, > + slice(insn, 21, 21) == 0, false); > +} > +// A7.7 > +// If L (Inst{21}) == 0, store instructions. > +// DblSpaced = true. > +static bool DisassembleVLDSTLaneDbl(MCInst &MI, unsigned Opcode, uint32_t insn, > + unsigned short NumOps, unsigned &NumOpsAdded) { > + > + return DisassembleVLDSTLane0(MI, Opcode, insn, NumOps, NumOpsAdded, > + slice(insn, 21, 21) == 0, true); > +} > + > +// VLDRQ (vldmia), VSTRQ (vstmia) > +// Qd Rn imm (AM4) > +static bool DisassembleVLDSTRQ(MCInst &MI, unsigned Opcode, uint32_t insn, > + unsigned short NumOps, unsigned &NumOpsAdded) { > + > + const TargetOperandInfo *OpInfo = ARMInsts[Opcode].OpInfo; > + > + assert(NumOps >= 3 && > + OpInfo[0].RegClass == ARM::QPRRegClassID && > + OpInfo[1].RegClass == ARM::GPRRegClassID && > + OpInfo[2].RegClass == 0); > + > + // Qd = Inst{22:15-12} => NEON Rd > + MI.addOperand(MCOperand::CreateReg( > + getRegisterEnum(ARM::QPRRegClassID, > + decodeNEONRd(insn), true))); > + > + // Rn = Inst{19-16} => ARM Rn > + MI.addOperand(MCOperand::CreateReg(getRegisterEnum(ARM::GPRRegClassID, > + decodeRn(insn)))); > + > + // Next comes the AM4 Opcode. > + assert(Opcode == ARM::VLDRQ || Opcode == ARM::VSTRQ); > + ARM_AM::AMSubMode SubMode = getAMSubModeForBits(getPUBits(insn)); > + bool WB = getWBit(insn) == 1; > + MI.addOperand(MCOperand::CreateImm(ARM_AM::getAM4ModeImm(SubMode, WB))); > + > + NumOpsAdded = 3; > + return true; > +} > + > +// VMOV (immediate) > +// Qd/Dd imm > +static bool DisassembleNVdImm(MCInst &MI, unsigned Opcode, uint32_t insn, > + unsigned short NumOps, unsigned &NumOpsAdded) { > + > + const TargetInstrDesc &TID = ARMInsts[Opcode]; > + const TargetOperandInfo *OpInfo = TID.OpInfo; > + > + assert(NumOps >= 2 && > + (OpInfo[0].RegClass == ARM::DPRRegClassID || > + OpInfo[0].RegClass == ARM::QPRRegClassID) && > + (OpInfo[1].RegClass == 0)); > + > + // Qd/Dd = Inst{22:15-12} => NEON Rd > + MI.addOperand(MCOperand::CreateReg(getRegisterEnum(OpInfo[0].RegClass, > + decodeNEONRd(insn)))); > + > + ElemSize esize = ESizeNA; > + switch (Opcode) { > + case ARM::VMOVv8i8: > + case ARM::VMOVv16i8: > + esize = ESize8; > + break; > + case ARM::VMOVv4i16: > + case ARM::VMOVv8i16: > + esize = ESize16; > + break; > + case ARM::VMOVv2i32: > + case ARM::VMOVv4i32: > + esize = ESize32; > + break; > + case ARM::VMOVv1i64: > + case ARM::VMOVv2i64: > + esize = ESize64; > + default: > + assert(0 && "Unreachable code!"); > + return false; > + } > + > + // One register and a modified immediate value. > + // Add the imm operand. > + MI.addOperand(MCOperand::CreateImm(decodeN1VImm(insn, esize))); > + > + NumOpsAdded = 2; > + return true; > +} > + > +namespace { > +enum N2VFlag { > + N2V_None, > + N2V_VectorDupLane, > + N2V_VectorShiftLeftLong, > + N2V_VectorConvert_Between_Float_Fixed > +}; > +} // End of unnamed namespace > + > +// Vector Convert [between floating-point and fixed-point] > +// Qd/Dd Qm/Dm [fbits] > +// > +// Vector Duplicate Lane (from scalar to all elements) Instructions. > +// VDUPLN16d, VDUPLN16q, VDUPLN32d, VDUPLN32q, VDUPLN8d, VDUPLN8q: > +// Qd/Dd Dm index > +// > +// Vector Shift Left Long (with maximum shift count) Instructions. > +// VSHLLi16, VSHLLi32, VSHLLi8: Qd Dm imm (== size) > +// > +// Vector Move Long: > +// Qd Dm > +// > +// Vector Move Narrow: > +// Dd Qm > +// > +// Others > +static bool DisassembleNVdVmImm0(MCInst &MI, unsigned Opc, uint32_t insn, > + unsigned short NumOps, unsigned &NumOpsAdded, N2VFlag Flag = N2V_None) { > + > + const TargetInstrDesc &TID = ARMInsts[Opc]; > + const TargetOperandInfo *OpInfo = TID.OpInfo; > + > + assert(NumOps >= 2 && > + (OpInfo[0].RegClass == ARM::DPRRegClassID || > + OpInfo[0].RegClass == ARM::QPRRegClassID) && > + (OpInfo[1].RegClass == ARM::DPRRegClassID || > + OpInfo[1].RegClass == ARM::QPRRegClassID)); > + > + unsigned &OpIdx = NumOpsAdded; > + > + OpIdx = 0; > + > + ElemSize esize = ESizeNA; > + if (Flag == N2V_VectorShiftLeftLong) { > + // VSHLL has maximum shift count as the imm, inferred from its size. > + assert(Opc == ARM::VSHLLi16 || Opc == ARM::VSHLLi32 || Opc == ARM::VSHLLi8); > + esize = Opc == ARM::VSHLLi8 ? ESize8 > + : (Opc == ARM::VSHLLi16 ? ESize16 > + : ESize32); > + } > + if (Flag == N2V_VectorDupLane) { > + // VDUPLN has its index embedded. Its size can be inferred from the Opcode. > + assert(Opc >= ARM::VDUPLN16d && Opc <= ARM::VDUPLN8q); > + esize = (Opc == ARM::VDUPLN8d || Opc == ARM::VDUPLN8q) ? ESize8 > + : ((Opc == ARM::VDUPLN16d || Opc == ARM::VDUPLN16q) ? ESize16 > + : ESize32); > + } > + > + // Qd/Dd = Inst{22:15-12} => NEON Rd > + MI.addOperand(MCOperand::CreateReg(getRegisterEnum(OpInfo[OpIdx].RegClass, > + decodeNEONRd(insn)))); > + ++OpIdx; > + > + // VPADAL... > + if (TID.getOperandConstraint(OpIdx, TOI::TIED_TO) != -1) { > + // TIED_TO operand. > + MI.addOperand(MCOperand::CreateReg(0)); > + ++OpIdx; > + } > + > + // Dm = Inst{5:3-0} => NEON Rm > + MI.addOperand(MCOperand::CreateReg(getRegisterEnum(OpInfo[OpIdx].RegClass, > + decodeNEONRm(insn)))); > + ++OpIdx; > + > + // Add the imm operand, if required. > + if (OpIdx < NumOps && OpInfo[OpIdx].RegClass == 0 > + && !OpInfo[OpIdx].isPredicate() && !OpInfo[OpIdx].isOptionalDef()) { > + > + unsigned imm = 0xFFFFFFFF; > + > + if (Flag == N2V_VectorShiftLeftLong) > + imm = static_cast(esize); > + if (Flag == N2V_VectorDupLane) > + imm = decodeNVLaneDupIndex(insn, esize); > + if (Flag == N2V_VectorConvert_Between_Float_Fixed) > + imm = decodeVCVTFractionBits(insn); > + > + assert(imm != 0xFFFFFFFF); > + MI.addOperand(MCOperand::CreateImm(imm)); > + ++OpIdx; > + } > + > + return true; > +} > + > +static bool DisassembleNVdVmImm(MCInst &MI, unsigned Opc, uint32_t insn, > + unsigned short NumOps, unsigned &NumOpsAdded) { > + > + return DisassembleNVdVmImm0(MI, Opc, insn, NumOps, NumOpsAdded); > +} > +static bool DisassembleNVdVmImmVCVT(MCInst &MI, unsigned Opc, uint32_t insn, > + unsigned short NumOps, unsigned &NumOpsAdded) { > + > + return DisassembleNVdVmImm0(MI, Opc, insn, NumOps, NumOpsAdded, > + N2V_VectorConvert_Between_Float_Fixed); > +} > +static bool DisassembleNVdVmImmVDupLane(MCInst &MI, unsigned Opc, uint32_t insn, > + unsigned short NumOps, unsigned &NumOpsAdded) { > + > + return DisassembleNVdVmImm0(MI, Opc, insn, NumOps, NumOpsAdded, > + N2V_VectorDupLane); > +} > +static bool DisassembleNVdVmImmVSHLL(MCInst &MI, unsigned Opc, uint32_t insn, > + unsigned short NumOps, unsigned &NumOpsAdded) { > + > + return DisassembleNVdVmImm0(MI, Opc, insn, NumOps, NumOpsAdded, > + N2V_VectorShiftLeftLong); > +} > + > +// Vector Transpose/Unzip/Zip Instructions > +// Qd/Dd Qm/Dm [Qd/Dd (TIED_TO)] [Qm/Dm (TIED_TO)] > +static bool DisassembleNVectorShuffle(MCInst &MI,unsigned Opcode,uint32_t insn, > + unsigned short NumOps, unsigned &NumOpsAdded) { > + > + const TargetInstrDesc &TID = ARMInsts[Opcode]; > + const TargetOperandInfo *OpInfo = TID.OpInfo; > + > + assert(NumOps >= 4 && > + (OpInfo[0].RegClass == ARM::DPRRegClassID || > + OpInfo[0].RegClass == ARM::QPRRegClassID) && > + (OpInfo[1].RegClass == ARM::DPRRegClassID || > + OpInfo[1].RegClass == ARM::QPRRegClassID) && > + (OpInfo[2].RegClass == ARM::DPRRegClassID || > + OpInfo[2].RegClass == ARM::QPRRegClassID) && > + (OpInfo[3].RegClass == ARM::DPRRegClassID || > + OpInfo[3].RegClass == ARM::QPRRegClassID)); > + > + unsigned &OpIdx = NumOpsAdded; > + > + OpIdx = 0; > + > + // Qd/Dd = Inst{22:15-12} => NEON Rd > + MI.addOperand(MCOperand::CreateReg(getRegisterEnum(OpInfo[OpIdx].RegClass, > + decodeNEONRd(insn)))); > + ++OpIdx; > + > + // Dm = Inst{5:3-0} => NEON Rm > + MI.addOperand(MCOperand::CreateReg(getRegisterEnum(OpInfo[OpIdx].RegClass, > + decodeNEONRm(insn)))); > + ++OpIdx; > + > + assert(TID.getOperandConstraint(OpIdx, TOI::TIED_TO) != -1 && > + TID.getOperandConstraint(OpIdx+1, TOI::TIED_TO) != -1); > + > + MI.addOperand(MCOperand::CreateReg(0)); ++OpIdx; > + MI.addOperand(MCOperand::CreateReg(0)); ++OpIdx; > + > + return true; > +} > + > +// Vector Shift [Accumulate] Instructions. > +// Qd/Dd [Qd/Dd (TIED_TO)] Qm/Dm ShiftAmt > +static bool DisassembleNVectorShift0(MCInst &MI, unsigned Opcode, uint32_t insn, > + unsigned short NumOps, unsigned &NumOpsAdded, bool NormalShift = true) { > + > + const TargetInstrDesc &TID = ARMInsts[Opcode]; > + const TargetOperandInfo *OpInfo = TID.OpInfo; > + > + assert(NumOps >= 3 && > + (OpInfo[0].RegClass == ARM::DPRRegClassID || > + OpInfo[0].RegClass == ARM::QPRRegClassID) && > + (OpInfo[1].RegClass == ARM::DPRRegClassID || > + OpInfo[1].RegClass == ARM::QPRRegClassID)); > + > + unsigned &OpIdx = NumOpsAdded; > + > + OpIdx = 0; > + > + // Qd/Dd = Inst{22:15-12} => NEON Rd > + MI.addOperand(MCOperand::CreateReg(getRegisterEnum(OpInfo[OpIdx].RegClass, > + decodeNEONRd(insn)))); > + ++OpIdx; > + > + if (TID.getOperandConstraint(OpIdx, TOI::TIED_TO) != -1) { > + // TIED_TO operand. > + MI.addOperand(MCOperand::CreateReg(0)); > + ++OpIdx; > + } > + > + assert(OpInfo[OpIdx].RegClass == ARM::DPRRegClassID || > + OpInfo[OpIdx].RegClass == ARM::QPRRegClassID); > + > + // Qm/Dm = Inst{5:3-0} => NEON Rm > + MI.addOperand(MCOperand::CreateReg(getRegisterEnum(OpInfo[OpIdx].RegClass, > + decodeNEONRm(insn)))); > + ++OpIdx; > + > + assert(OpInfo[OpIdx].RegClass == 0); > + > + // Add the imm operand. > + MI.addOperand(MCOperand::CreateImm(decodeNVSAmt(insn, NormalShift))); > + ++OpIdx; > + > + return true; > +} > + > +// Normal shift amount interpretation. > +static bool DisassembleNVectorShift(MCInst &MI, unsigned Opcode, uint32_t insn, > + unsigned short NumOps, unsigned &NumOpsAdded) { > + > + return DisassembleNVectorShift0(MI, Opcode, insn, NumOps, NumOpsAdded, true); > +} > +// Different shift amount interpretation. > +static bool DisassembleNVectorShift2(MCInst &MI, unsigned Opcode, uint32_t insn, > + unsigned short NumOps, unsigned &NumOpsAdded) { > + > + return DisassembleNVectorShift0(MI, Opcode, insn, NumOps, NumOpsAdded, false); > +} > + > +namespace { > +enum N3VFlag { > + N3V_None, > + N3V_VectorExtract, > + N3V_VectorShift, > + N3V_Multiply_By_Scalar > +}; > +} // End of unnamed namespace > + > +// NEON Three Register Instructions with Optional Immediate Operand > +// > +// Vector Extract Instructions. > +// Qd/Dd Qn/Dn Qm/Dm imm4 > +// > +// Vector Shift (Register) Instructions. > +// Qd/Dd Qm/Dm Qn/Dn (notice the order of m, n) > +// > +// Vector Multiply [Accumulate/Subtract] [Long] By Scalar Instructions. > +// Qd/Dd Qn/Dn RestrictedDm index > +// > +// Others > +static bool DisassembleNVdVnVmImm0(MCInst &MI, unsigned Opcode, uint32_t insn, > + unsigned short NumOps, unsigned &NumOpsAdded, N3VFlag Flag = N3V_None) { > + > + const TargetInstrDesc &TID = ARMInsts[Opcode]; > + const TargetOperandInfo *OpInfo = TID.OpInfo; > + > + assert(NumOps >= 3 && > + (OpInfo[0].RegClass == ARM::DPRRegClassID || > + OpInfo[0].RegClass == ARM::QPRRegClassID) && > + (OpInfo[1].RegClass == ARM::DPRRegClassID || > + OpInfo[1].RegClass == ARM::QPRRegClassID) && > + (OpInfo[2].RegClass != 0)); > + > + unsigned &OpIdx = NumOpsAdded; > + > + OpIdx = 0; > + > + bool VdVnVm = Flag == N3V_VectorShift ? false : true; > + bool IsImm4 = Flag == N3V_VectorExtract ? true : false; > + bool IsDmRestricted = Flag == N3V_Multiply_By_Scalar ? true : false; > + ElemSize esize = ESizeNA; > + if (Flag == N3V_Multiply_By_Scalar) { > + unsigned size = (insn >> 20) & 3; > + if (size == 1) esize = ESize16; > + if (size == 2) esize = ESize32; > + assert (esize == ESize16 || esize == ESize32); > + } > + > + // Qd/Dd = Inst{22:15-12} => NEON Rd > + MI.addOperand(MCOperand::CreateReg(getRegisterEnum(OpInfo[OpIdx].RegClass, > + decodeNEONRd(insn)))); > + ++OpIdx; > + > + // VABA, VABAL, VBSLd, VBSLq, ... > + if (TID.getOperandConstraint(OpIdx, TOI::TIED_TO) != -1) { > + // TIED_TO operand. > + MI.addOperand(MCOperand::CreateReg(0)); > + ++OpIdx; > + } > + > + // Dn = Inst{7:19-16} => NEON Rn > + // or > + // Dm = Inst{5:3-0} => NEON Rm > + MI.addOperand(MCOperand::CreateReg( > + getRegisterEnum(OpInfo[OpIdx].RegClass, > + VdVnVm ? decodeNEONRn(insn) > + : decodeNEONRm(insn)))); > + ++OpIdx; > + > + // Dm = Inst{5:3-0} => NEON Rm > + // or > + // Dm is restricted to D0-D7 if size is 16, D0-D15 otherwise > + // or > + // Dn = Inst{7:19-16} => NEON Rn > + unsigned m = VdVnVm ? (IsDmRestricted ? decodeRestrictedDm(insn, esize) > + : decodeNEONRm(insn)) > + : decodeNEONRn(insn); > + > + MI.addOperand(MCOperand::CreateReg( > + getRegisterEnum(OpInfo[OpIdx].RegClass, m))); > + ++OpIdx; > + > + if (OpIdx < NumOps && OpInfo[OpIdx].RegClass == 0 > + && !OpInfo[OpIdx].isPredicate() && !OpInfo[OpIdx].isOptionalDef()) { > + // Add the imm operand. > + unsigned Imm = 0; > + if (IsImm4) > + Imm = decodeN3VImm(insn); > + else if (IsDmRestricted) > + Imm = decodeRestrictedDmIndex(insn, esize); > + else > + assert(0 && "Internal error: unreachable code!"); > + > + MI.addOperand(MCOperand::CreateImm(Imm)); > + ++OpIdx; > + } > + > + return true; > +} > + > +static bool DisassembleNVdVnVmImm(MCInst &MI, unsigned Opcode, uint32_t insn, > + unsigned short NumOps, unsigned &NumOpsAdded) { > + > + return DisassembleNVdVnVmImm0(MI, Opcode, insn, NumOps, NumOpsAdded); > +} > +static bool DisassembleNVdVnVmImmVectorShift(MCInst &MI, unsigned Opcode, > + uint32_t insn, unsigned short NumOps, unsigned &NumOpsAdded) { > + > + return DisassembleNVdVnVmImm0(MI, Opcode, insn, NumOps, NumOpsAdded, > + N3V_VectorShift); > +} > +static bool DisassembleNVdVnVmImmVectorExtract(MCInst &MI, unsigned Opcode, > + uint32_t insn, unsigned short NumOps, unsigned &NumOpsAdded) { > + > + return DisassembleNVdVnVmImm0(MI, Opcode, insn, NumOps, NumOpsAdded, > + N3V_VectorExtract); > +} > +static bool DisassembleNVdVnVmImmMulScalar(MCInst &MI, unsigned Opcode, > + uint32_t insn, unsigned short NumOps, unsigned &NumOpsAdded) { > + > + return DisassembleNVdVnVmImm0(MI, Opcode, insn, NumOps, NumOpsAdded, > + N3V_Multiply_By_Scalar); > +} > + > +// Vector Table Lookup > +// > +// VTBL1, VTBX1: Dd [Dd(TIED_TO)] Dn Dm > +// VTBL2, VTBX2: Dd [Dd(TIED_TO)] Dn Dn+1 Dm > +// VTBL3, VTBX3: Dd [Dd(TIED_TO)] Dn Dn+1 Dn+2 Dm > +// VTBL4, VTBX4: Dd [Dd(TIED_TO)] Dn Dn+1 Dn+2 Dn+3 Dm > +static bool DisassembleVTBL(MCInst &MI, unsigned Opcode, uint32_t insn, > + unsigned short NumOps, unsigned &NumOpsAdded) { > + > + const TargetInstrDesc &TID = ARMInsts[Opcode]; > + const TargetOperandInfo *OpInfo = TID.OpInfo; > + > + assert(NumOps >= 3 && > + OpInfo[0].RegClass == ARM::DPRRegClassID && > + OpInfo[1].RegClass == ARM::DPRRegClassID && > + OpInfo[2].RegClass == ARM::DPRRegClassID); > + > + unsigned &OpIdx = NumOpsAdded; > + > + OpIdx = 0; > + > + unsigned Rn = decodeNEONRn(insn); > + > + // {Dn} encoded as len = 0b00 > + // {Dn Dn+1} encoded as len = 0b01 > + // {Dn Dn+1 Dn+2 } encoded as len = 0b10 > + // {Dn Dn+1 Dn+2 Dn+3} encoded as len = 0b11 > + unsigned Len = slice(insn, 9, 8) + 1; > + > + // Dd (the destination vector) > + MI.addOperand(MCOperand::CreateReg(getRegisterEnum(ARM::DPRRegClassID, > + decodeNEONRd(insn)))); > + ++OpIdx; > + > + // Process tied_to operand constraint. > + int Idx; > + if ((Idx = TID.getOperandConstraint(OpIdx, TOI::TIED_TO)) != -1) { > + MI.addOperand(MI.getOperand(Idx)); > + ++OpIdx; > + } > + > + // Do the now. > + for (unsigned i = 0; i < Len; ++i) { > + assert(OpIdx < NumOps && OpInfo[OpIdx].RegClass == ARM::DPRRegClassID); > + MI.addOperand(MCOperand::CreateReg(getRegisterEnum(ARM::DPRRegClassID, > + Rn + i))); > + ++OpIdx; > + } > + > + // Dm (the index vector) > + assert(OpIdx < NumOps && OpInfo[OpIdx].RegClass == ARM::DPRRegClassID); > + MI.addOperand(MCOperand::CreateReg(getRegisterEnum(ARM::DPRRegClassID, > + decodeNEONRm(insn)))); > + ++OpIdx; > + > + return true; > +} > + > +/// NEONFuncPtrs - NEONFuncPtrs maps NSFormat to corresponding DisassembleFP. > +/// We divide the disassembly task into different categories, with each one > +/// corresponding to a specific instruction encoding format. There could be > +/// exceptions when handling a specific format, and that is why the Opcode is > +/// also present in the function prototype. > +static const DisassembleFP NEONFuncPtrs[] = { > + // This will assert(). > + &DisassembleNSFormatNone, > + > + // VLD and VST (including one lane) Instructions. > + &DisassembleVLDSTLane, > + > + // VLD and VST (including one lane) Double-Spaced Instructions. > + &DisassembleVLDSTLaneDbl, > + > + // A8.6.319 VLDM & A8.6.399 VSTM > + // LLVM defines VLDRQ/VSTRQ to load/store a Q register as a D register pair. > + &DisassembleVLDSTRQ, > + > + // A7.4.6 One register and a modified immediate value > + // 1-Register Instructions with imm. > + // LLVM only defines VMOVv instructions. > + &DisassembleNVdImm, > + > + // 2-Register Instructions with no imm. > + &DisassembleNVdVmImm, > + > + // 2-Register Instructions with imm (vector convert float/fixed point). > + &DisassembleNVdVmImmVCVT, > + > + // 2-Register Instructions with imm (vector dup lane). > + &DisassembleNVdVmImmVDupLane, > + > + // 2-Register Instructions with imm (vector shift left long). > + &DisassembleNVdVmImmVSHLL, > + > + // Vector Transpose/Unzip/Zip Instructions. > + &DisassembleNVectorShuffle, > + > + // Vector Shift [Narrow Accumulate] Instructions. > + &DisassembleNVectorShift, > + > + // Vector Shift Instructions with different interpretation of shift amount. > + &DisassembleNVectorShift2, > + > + // 3-Register Data-Processing Instructions. > + &DisassembleNVdVnVmImm, > + > + // Vector Shift (Register) Instructions. > + // D:Vd M:Vm N:Vn (notice that M:Vm is the first operand) > + &DisassembleNVdVnVmImmVectorShift, > + > + // Vector Extract Instructions. > + &DisassembleNVdVnVmImmVectorExtract, > + > + // Vector [Saturating Rounding Doubling] Multiply [Accumulate/Subtract] [Long] > + // By Scalar Instructions. > + &DisassembleNVdVnVmImmMulScalar, > + > + // Vector Table Lookup uses byte indexes in a control vector to look up byte > + // values in a table and generate a new vector. > + &DisassembleVTBL, > + NULL, > +}; > + > +static bool DisassembleNEONFrm(MCInst &MI, unsigned Opcode, uint32_t insn, > + unsigned short NumOps, unsigned &NumOpsAdded) { > + assert(0 && "Code is not reachable"); > + return false; > +} > + > +// Vector Get Lane (move scalar to ARM core register) Instructions. > +// VGETLNi32, VGETLNs16, VGETLNs8, VGETLNu16, VGETLNu8: Rt Dn index > +static bool DisassembleNEONGetLnFrm(MCInst &MI, unsigned Opcode, uint32_t insn, > + unsigned short NumOps, unsigned &NumOpsAdded) { > + > + const TargetInstrDesc &TID = ARMInsts[Opcode]; > + unsigned short NumDefs = TID.getNumDefs(); > + const TargetOperandInfo *OpInfo = TID.OpInfo; > + > + assert(NumDefs == 1 && NumOps >= 3 && > + OpInfo[0].RegClass == ARM::GPRRegClassID && > + OpInfo[1].RegClass == ARM::DPRRegClassID && > + OpInfo[2].RegClass == 0); > + > + ElemSize esize = > + Opcode == ARM::VGETLNi32 ? ESize32 > + : ((Opcode == ARM::VGETLNs16 || Opcode == ARM::VGETLNu16) ? ESize16 > + : ESize32); > + > + // Rt = Inst{15-12} => ARM Rd > + MI.addOperand(MCOperand::CreateReg(getRegisterEnum(ARM::GPRRegClassID, > + decodeRd(insn)))); > + > + // Dn = Inst{7:19-16} => NEON Rn > + MI.addOperand(MCOperand::CreateReg(getRegisterEnum(ARM::DPRRegClassID, > + decodeNEONRn(insn)))); > + > + MI.addOperand(MCOperand::CreateImm(decodeNVLaneOpIndex(insn, esize))); > + > + NumOpsAdded = 3; > + return true; > +} > + > +// Vector Set Lane (move ARM core register to scalar) Instructions. > +// VSETLNi16, VSETLNi32, VSETLNi8: Dd Dd (TIED_TO) Rt index > +static bool DisassembleNEONSetLnFrm(MCInst &MI, unsigned Opcode, uint32_t insn, > + unsigned short NumOps, unsigned &NumOpsAdded) { > + > + const TargetInstrDesc &TID = ARMInsts[Opcode]; > + unsigned short NumDefs = TID.getNumDefs(); > + const TargetOperandInfo *OpInfo = TID.OpInfo; > + > + assert(NumDefs == 1 && NumOps >= 3 && > + OpInfo[0].RegClass == ARM::DPRRegClassID && > + OpInfo[1].RegClass == ARM::DPRRegClassID && > + TID.getOperandConstraint(1, TOI::TIED_TO) != -1 && > + OpInfo[2].RegClass == ARM::GPRRegClassID && > + OpInfo[3].RegClass == 0); > + > + ElemSize esize = > + Opcode == ARM::VSETLNi8 ? ESize8 > + : (Opcode == ARM::VSETLNi16 ? ESize16 > + : ESize32); > + > + // Dd = Inst{7:19-16} => NEON Rn > + MI.addOperand(MCOperand::CreateReg(getRegisterEnum(ARM::DPRRegClassID, > + decodeNEONRn(insn)))); > + > + // TIED_TO operand. > + MI.addOperand(MCOperand::CreateReg(0)); > + > + // Rt = Inst{15-12} => ARM Rd > + MI.addOperand(MCOperand::CreateReg(getRegisterEnum(ARM::GPRRegClassID, > + decodeRd(insn)))); > + > + MI.addOperand(MCOperand::CreateImm(decodeNVLaneOpIndex(insn, esize))); > + > + NumOpsAdded = 4; > + return true; > +} > + > +// Vector Duplicate Instructions (from ARM core register to all elements). > +// VDUP8d, VDUP16d, VDUP32d, VDUP8q, VDUP16q, VDUP32q: Qd/Dd Rt > +static bool DisassembleNEONDupFrm(MCInst &MI, unsigned Opcode, uint32_t insn, > + unsigned short NumOps, unsigned &NumOpsAdded) { > + > + const TargetOperandInfo *OpInfo = ARMInsts[Opcode].OpInfo; > + > + assert(NumOps >= 2 && > + (OpInfo[0].RegClass == ARM::DPRRegClassID || > + OpInfo[0].RegClass == ARM::QPRRegClassID) && > + OpInfo[1].RegClass == ARM::GPRRegClassID); > + > + unsigned RegClass = OpInfo[0].RegClass; > + > + // Qd/Dd = Inst{7:19-16} => NEON Rn > + MI.addOperand(MCOperand::CreateReg(getRegisterEnum(RegClass, > + decodeNEONRn(insn)))); > + > + // Rt = Inst{15-12} => ARM Rd > + MI.addOperand(MCOperand::CreateReg(getRegisterEnum(ARM::GPRRegClassID, > + decodeRd(insn)))); > + > + NumOpsAdded = 2; > + return true; > +} > + > +// A8.6.41 DMB > +// A8.6.42 DSB > +// A8.6.49 ISB > +static inline bool MemBarrierInstr(uint32_t insn) { > + unsigned op7_4 = slice(insn, 7, 4); > + if (slice(insn, 31, 20) == 0xf57 && (op7_4 >= 4 && op7_4 <= 6)) > + return true; > + > + return false; > +} > + > +static inline bool PreLoadOpcode(unsigned Opcode) { > + switch(Opcode) { > + case ARM::PLDi: case ARM::PLDr: > + case ARM::PLDWi: case ARM::PLDWr: > + case ARM::PLIi: case ARM::PLIr: > + return true; > + default: > + return false; > + } > +} > + > +static bool DisassemblePreLoadFrm(MCInst &MI, unsigned Opcode, uint32_t insn, > + unsigned short NumOps, unsigned &NumOpsAdded) { > + > + // Preload Data/Instruction requires either 2 or 4 operands. > + // PLDi, PLDWi, PLIi: Rn [+/-]imm12 add = (U == '1') > + // PLDr[a|m], PLDWr[a|m], PLIr[a|m]: Rn Rm addrmode2_opc > + > + MI.addOperand(MCOperand::CreateReg(getRegisterEnum(ARM::GPRRegClassID, > + decodeRn(insn)))); > + > + if (Opcode == ARM::PLDi || Opcode == ARM::PLDWi || Opcode == ARM::PLIi) { > + unsigned Imm12 = slice(insn, 11, 0); > + bool Negative = getUBit(insn) == 0; > + int Offset = Negative ? -1 - Imm12 : 1 * Imm12; > + MI.addOperand(MCOperand::CreateImm(Offset)); > + NumOpsAdded = 2; > + } else { > + MI.addOperand(MCOperand::CreateReg(getRegisterEnum(ARM::GPRRegClassID, > + decodeRm(insn)))); > + > + ARM_AM::AddrOpc AddrOpcode = getUBit(insn) ? ARM_AM::add : ARM_AM::sub; > + > + // Inst{6-5} encodes the shift opcode. > + ARM_AM::ShiftOpc ShOp = getShiftOpcForBits(slice(insn, 6, 5)); > + // Inst{11-7} encodes the imm5 shift amount. > + unsigned ShImm = slice(insn, 11, 7); > + > + // A8.4.1. Possible rrx or shift amount of 32... > + getImmShiftSE(ShOp, ShImm); > + MI.addOperand(MCOperand::CreateImm( > + ARM_AM::getAM2Opc(AddrOpcode, ShImm, ShOp))); > + NumOpsAdded = 3; > + } > + > + return true; > +} > + > +static bool DisassembleMiscFrm(MCInst &MI, unsigned Opcode, uint32_t insn, > + unsigned short NumOps, unsigned &NumOpsAdded) { > + > + if (MemBarrierInstr(insn)) > + return true; > + > + switch (Opcode) { > + case ARM::CLREX: > + case ARM::NOP: > + case ARM::TRAP: > + case ARM::YIELD: > + case ARM::WFE: > + case ARM::WFI: > + case ARM::SEV: > + case ARM::SETENDBE: > + case ARM::SETENDLE: > + return true; > + default: > + break; > + } > + > + // CPS has a singleton $opt operand that contains the following information: > + // opt{4-0} = mode from Inst{4-0} > + // opt{5} = changemode from Inst{17} > + // opt{8-6} = AIF from Inst{8-6} > + // opt{10-9} = imod from Inst{19-18} with 0b10 as enable and 0b11 as disable > + if (Opcode == ARM::CPS) { > + unsigned Option = slice(insn, 4, 0) | slice(insn, 17, 17) << 5 | > + slice(insn, 8, 6) << 6 | slice(insn, 19, 18) << 9; > + MI.addOperand(MCOperand::CreateImm(Option)); > + NumOpsAdded = 1; > + return true; > + } > + > + // DBG has its option specified in Inst{3-0}. > + if (Opcode == ARM::DBG) { > + MI.addOperand(MCOperand::CreateImm(slice(insn, 3, 0))); > + NumOpsAdded = 1; > + return true; > + } > + > + // BKPT takes an imm32 val equal to ZeroExtend(Inst{19-8:3-0}). > + if (Opcode == ARM::BKPT) { > + MI.addOperand(MCOperand::CreateImm(slice(insn, 19, 8) << 4 | > + slice(insn, 3, 0))); > + NumOpsAdded = 1; > + return true; > + } > + > + if (PreLoadOpcode(Opcode)) > + return DisassemblePreLoadFrm(MI, Opcode, insn, NumOps, NumOpsAdded); > + > + assert(0 && "Unexpected misc instruction!"); > + return false; > +} > + > +static bool DisassembleThumbMiscFrm(MCInst &MI, unsigned Opcode, uint32_t insn, > + unsigned short NumOps, unsigned &NumOpsAdded) { > + > + assert(0 && "Unexpected thumb misc. instruction!"); > + return false; > +} > + > +/// FuncPtrs - FuncPtrs maps ARMFormat to its corresponding DisassembleFP. > +/// We divide the disassembly task into different categories, with each one > +/// corresponding to a specific instruction encoding format. There could be > +/// exceptions when handling a specific format, and that is why the Opcode is > +/// also present in the function prototype. > +static const DisassembleFP FuncPtrs[] = { > + &DisassemblePseudo, > + &DisassembleMulFrm, > + &DisassembleBrFrm, > + &DisassembleBrMiscFrm, > + &DisassembleDPFrm, > + &DisassembleDPSoRegFrm, > + &DisassembleLdFrm, > + &DisassembleStFrm, > + &DisassembleLdMiscFrm, > + &DisassembleStMiscFrm, > + &DisassembleLdStMulFrm, > + &DisassembleArithMiscFrm, > + &DisassembleExtFrm, > + &DisassembleVFPUnaryFrm, > + &DisassembleVFPBinaryFrm, > + &DisassembleVFPConv1Frm, > + &DisassembleVFPConv2Frm, > + &DisassembleVFPConv3Frm, > + &DisassembleVFPConv4Frm, > + &DisassembleVFPConv5Frm, > + &DisassembleVFPLdStFrm, > + &DisassembleVFPLdStMulFrm, > + &DisassembleVFPMiscFrm, > + &DisassembleThumbFrm, > + &DisassembleNEONFrm, > + &DisassembleNEONGetLnFrm, > + &DisassembleNEONSetLnFrm, > + &DisassembleNEONDupFrm, > + &DisassembleLdStExFrm, > + &DisassembleMiscFrm, > + &DisassembleThumbMiscFrm, > + NULL, > +}; > + > +/// ARMAlgorithm - ARMAlgorithm implements ARMDisassemblyAlgorithm for solving > +/// the problem of building the MCOperands of an MCInst. Construction of > +/// ARMAlgorithm requires passing in a function pointer with the DisassembleFP > +/// data type. > +class ARMAlgorithm : public ARMDisassemblyAlgorithm { > + /// Algorithms - Algorithms stores a map from Format to ARMAlgorithm*. > + static std::vector Algorithms; > + /// NSAlgorithms - NSAlgorithms stores a map from NSFormat to ARMAlgorithm*. > + static std::vector NSAlgorithms; > + > + DisassembleFP Disassemble; > + > +public: > + /// GetInstance - GetInstance returns an instance of ARMAlgorithm given the > + /// encoding Format. API clients should not free up the returned instance. > + static ARMAlgorithm *GetInstance(ARMFormat Format, NSFormat NSF) { > + /// Init the first time. > + if (Algorithms.size() == 0) { > + Algorithms.resize(array_lengthof(FuncPtrs)); > + for (unsigned i = 0, num = array_lengthof(FuncPtrs); i < num; ++i) > + if (FuncPtrs[i]) > + Algorithms[i] = new ARMAlgorithm(FuncPtrs[i]); > + else > + Algorithms[i] = NULL; > + } > + if (NSAlgorithms.size() == 0) { > + NSAlgorithms.resize(array_lengthof(NEONFuncPtrs)); > + for (unsigned i = 0, num = array_lengthof(NEONFuncPtrs); i < num; ++i) > + if (NEONFuncPtrs[i]) > + NSAlgorithms[i] = new ARMAlgorithm(NEONFuncPtrs[i]); > + else > + NSAlgorithms[i] = NULL; > + } > + > + if (Format != ARM_FORMAT_NEONFRM) > + return Algorithms[Format]; > + else > + return NSAlgorithms[NSF]; > + } > + > + virtual bool Solve(MCInst &MI, unsigned Opcode, uint32_t insn, > + unsigned short NumOps, unsigned &NumOpsAdded) const { > + if (Disassemble == NULL) > + return false; > + > + return (*Disassemble)(MI, Opcode, insn, NumOps, NumOpsAdded); > + } > + > +private: > + ARMAlgorithm(DisassembleFP fp) : > + ARMDisassemblyAlgorithm(), Disassemble(fp) {} > + > + ARMAlgorithm(ARMAlgorithm &AA) : > + ARMDisassemblyAlgorithm(), Disassemble(AA.Disassemble) {} > + > + virtual ~ARMAlgorithm() {} > +}; > + > +// Define the symbol here. > +std::vector ARMAlgorithm::Algorithms; > + > +// Define the symbol here. > +std::vector ARMAlgorithm::NSAlgorithms; > + > +// Define the symbol here. > +unsigned ARMBasicMCBuilder::ITCounter = 0; > + > +// Define the symbol here. > +unsigned ARMBasicMCBuilder::ITState = 0; > + > +// A8.6.50 > +static unsigned short CountITSize(unsigned ITMask) { > + // First count the trailing zeros of the IT mask. > + unsigned TZ = CountTrailingZeros_32(ITMask); > + assert(TZ <= 3); > + return (4 - TZ); > +} > + > +/// BuildIt - BuildIt performs the build step for this ARM Basic MC Builder. > +/// The general idea is to set the Opcode for the MCInst, followed by adding > +/// the appropriate MCOperands to the MCInst. ARM Basic MC Builder delegates > +/// to the Algo (ARM Disassemble Algorithm) object to perform Format-specific > +/// disassembly, followed by class method TryPredicateAndSBitModifier() to do > +/// PredicateOperand and OptionalDefOperand which follow the Dst/Src Operands. > +bool ARMBasicMCBuilder::BuildIt(MCInst &MI, uint32_t insn) { > + // Stage 1 sets the Opcode. > + MI.setOpcode(Opcode); > + // If the number of operands is zero, we're done! > + if (NumOps == 0) > + return true; > + > + // Stage 2 calls the ARM Disassembly Algorithm to build the operand list. > + unsigned NumOpsAdded = 0; > + bool OK = Algo.Solve(MI, Opcode, insn, NumOps, NumOpsAdded); > + > + if (!OK) return false; > + if (NumOpsAdded >= NumOps) > + return true; > + > + // Stage 3 deals with operands unaccounted for after stage 2 is finished. > + // FIXME: Should this be done selectively? > + return TryPredicateAndSBitModifier(MI, Opcode, insn, NumOps - NumOpsAdded); > +} > + > +bool ARMBasicMCBuilder::TryPredicateAndSBitModifier(MCInst& MI, unsigned Opcode, > + uint32_t insn, unsigned short NumOpsRemaining) { > + > + assert(NumOpsRemaining > 0); > + > + const TargetOperandInfo *OpInfo = ARMInsts[Opcode].OpInfo; > + const std::string &Name = ARMInsts[Opcode].Name; > + unsigned Idx = MI.getNumOperands(); > + > + // First, we check whether this instr specifies the PredicateOperand through > + // a pair of TargetOperandInfos with isPredicate() property. > + if (NumOpsRemaining >= 2 && > + OpInfo[Idx].isPredicate() && OpInfo[Idx+1].isPredicate() && > + OpInfo[Idx].RegClass == 0 && OpInfo[Idx+1].RegClass == ARM::CCRRegClassID) > + { > + // If we are inside an IT block, get the IT condition bits maintained via > + // ARMBasicMCBuilder::ITState[7:0], through ARMBasicMCBuilder::GetITCond(). > + // See also A2.5.2. > + if (InITBlock()) > + MI.addOperand(MCOperand::CreateImm(GetITCond())); > + else { > + if (Name.length() > 1 && Name[0] == 't') { > + // Thumb conditional branch instructions have their cond field embedded, > + // like ARM. > + // > + // A8.6.16 B > + if (Name == "t2Bcc") > + MI.addOperand(MCOperand::CreateImm(slice(insn, 25, 22))); > + else if (Name == "tBcc") > + MI.addOperand(MCOperand::CreateImm(slice(insn, 11, 8))); > + else > + MI.addOperand(MCOperand::CreateImm(ARMCC::AL)); > + } else { > + // ARM Instructions. Check condition field. > + int64_t CondVal = getCondField(insn); > + if (CondVal == 0xF) > + MI.addOperand(MCOperand::CreateImm(ARMCC::AL)); > + else > + MI.addOperand(MCOperand::CreateImm(CondVal)); > + } > + } > + MI.addOperand(MCOperand::CreateReg(ARM::CPSR)); > + Idx += 2; > + NumOpsRemaining -= 2; > + if (NumOpsRemaining == 0) > + return true; > + } > + > + assert(NumOpsRemaining > 0); > + > + // Next, if OptionalDefOperand exists, we check whether the 'S' bit is set. > + if (OpInfo[Idx].isOptionalDef() && OpInfo[Idx].RegClass==ARM::CCRRegClassID) { > + MI.addOperand(MCOperand::CreateReg(getSBit(insn) == 1 ? ARM::CPSR : 0)); > + --NumOpsRemaining; > + } > + > + if (NumOpsRemaining == 0) > + return true; > + else > + return false; > +} > + > +/// RunBuildAfterHook - RunBuildAfterHook performs operations deemed necessary > +/// after BuildIt is finished. > +bool ARMBasicMCBuilder::RunBuildAfterHook(bool Status, MCInst &MI, > + uint32_t insn) { > + > + if (Opcode == ARM::t2IT) { > + ARMBasicMCBuilder::ITCounter = CountITSize(slice(insn, 3, 0)); > + ARMBasicMCBuilder::InitITState(slice(insn, 7, 0)); > + } else if (InITBlock()) > + ARMBasicMCBuilder::UpdateITState(); > + > + return Status; > +} > + > +AbstractARMMCBuilder *ARMMCBuilderFactory::CreateMCBuilder(unsigned Opcode, > + ARMFormat Format, NSFormat NSF) { > + > + ARMAlgorithm *Algo = ARMAlgorithm::GetInstance(Format, NSF); > + if (!Algo) > + return NULL; > + > + return new ARMBasicMCBuilder(Opcode, Format, NSF, > + ARMInsts[Opcode].getNumOperands(), *Algo); > +} > > Added: llvm/trunk/lib/Target/ARM/Disassembler/ARMDisassemblerCore.h > URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Target/ARM/Disassembler/ARMDisassemblerCore.h?rev=98637&view=auto > ============================================================================== > --- llvm/trunk/lib/Target/ARM/Disassembler/ARMDisassemblerCore.h (added) > +++ llvm/trunk/lib/Target/ARM/Disassembler/ARMDisassemblerCore.h Tue Mar 16 11:36:54 2010 > @@ -0,0 +1,301 @@ > +//===- ARMDisassemblerCore.h - ARM disassembler helpers ----*- C++ -*-===// > +// > +// The LLVM Compiler Infrastructure > +// > +// This file is distributed under the University of Illinois Open Source > +// License. See LICENSE.TXT for details. > +// > +//===----------------------------------------------------------------------===// > +// > +// This file is part of the ARM Disassembler. > +// > +// The first part defines the enumeration type of ARM instruction format, which > +// specifies the encoding used by the instruction, as well as a helper function > +// to convert the enums to printable char strings. > +// > +// It also contains code to represent the concepts of Builder, Builder Factory, > +// as well as the Algorithm to solve the problem of disassembling an ARM instr. > +// > +//===----------------------------------------------------------------------===// > + > +#ifndef ARMDISASSEMBLERCORE_H > +#define ARMDISASSEMBLERCORE_H > + > +#include "llvm/MC/MCInst.h" > +#include "llvm/Target/TargetInstrInfo.h" > +#include "ARMInstrInfo.h" > + > +namespace llvm { > + > +class ARMUtils { > +public: > + static const char *OpcodeName(unsigned Opcode); > +}; > + > +#define ARM_FORMATS \ > + ENTRY(ARM_FORMAT_PSEUDO, 0) \ > + ENTRY(ARM_FORMAT_MULFRM, 1) \ > + ENTRY(ARM_FORMAT_BRFRM, 2) \ > + ENTRY(ARM_FORMAT_BRMISCFRM, 3) \ > + ENTRY(ARM_FORMAT_DPFRM, 4) \ > + ENTRY(ARM_FORMAT_DPSOREGFRM, 5) \ > + ENTRY(ARM_FORMAT_LDFRM, 6) \ > + ENTRY(ARM_FORMAT_STFRM, 7) \ > + ENTRY(ARM_FORMAT_LDMISCFRM, 8) \ > + ENTRY(ARM_FORMAT_STMISCFRM, 9) \ > + ENTRY(ARM_FORMAT_LDSTMULFRM, 10) \ > + ENTRY(ARM_FORMAT_ARITHMISCFRM, 11) \ > + ENTRY(ARM_FORMAT_EXTFRM, 12) \ > + ENTRY(ARM_FORMAT_VFPUNARYFRM, 13) \ > + ENTRY(ARM_FORMAT_VFPBINARYFRM, 14) \ > + ENTRY(ARM_FORMAT_VFPCONV1FRM, 15) \ > + ENTRY(ARM_FORMAT_VFPCONV2FRM, 16) \ > + ENTRY(ARM_FORMAT_VFPCONV3FRM, 17) \ > + ENTRY(ARM_FORMAT_VFPCONV4FRM, 18) \ > + ENTRY(ARM_FORMAT_VFPCONV5FRM, 19) \ > + ENTRY(ARM_FORMAT_VFPLDSTFRM, 20) \ > + ENTRY(ARM_FORMAT_VFPLDSTMULFRM, 21) \ > + ENTRY(ARM_FORMAT_VFPMISCFRM, 22) \ > + ENTRY(ARM_FORMAT_THUMBFRM, 23) \ > + ENTRY(ARM_FORMAT_NEONFRM, 24) \ > + ENTRY(ARM_FORMAT_NEONGETLNFRM, 25) \ > + ENTRY(ARM_FORMAT_NEONSETLNFRM, 26) \ > + ENTRY(ARM_FORMAT_NEONDUPFRM, 27) \ > + ENTRY(ARM_FORMAT_LDSTEXFRM, 28) \ > + ENTRY(ARM_FORMAT_MISCFRM, 29) \ > + ENTRY(ARM_FORMAT_THUMBMISCFRM, 30) > + > +// ARM instruction format specifies the encoding used by the instruction. > +#define ENTRY(n, v) n = v, > +typedef enum { > + ARM_FORMATS > + ARM_FORMAT_NA > +} ARMFormat; > +#undef ENTRY > + > +// Converts enum to const char*. > +static const inline char *stringForARMFormat(ARMFormat form) { > +#define ENTRY(n, v) case n: return #n; > + switch(form) { > + ARM_FORMATS > + case ARM_FORMAT_NA: > + default: > + return ""; > + } > +#undef ENTRY > +} > + > +#define NS_FORMATS \ > + ENTRY(NS_FORMAT_NONE, 0) \ > + ENTRY(NS_FORMAT_VLDSTLane, 1) \ > + ENTRY(NS_FORMAT_VLDSTLaneDbl, 2) \ > + ENTRY(NS_FORMAT_VLDSTRQ, 3) \ > + ENTRY(NS_FORMAT_NVdImm, 4) \ > + ENTRY(NS_FORMAT_NVdVmImm, 5) \ > + ENTRY(NS_FORMAT_NVdVmImmVCVT, 6) \ > + ENTRY(NS_FORMAT_NVdVmImmVDupLane, 7) \ > + ENTRY(NS_FORMAT_NVdVmImmVSHLL, 8) \ > + ENTRY(NS_FORMAT_NVectorShuffle, 9) \ > + ENTRY(NS_FORMAT_NVectorShift, 10) \ > + ENTRY(NS_FORMAT_NVectorShift2, 11) \ > + ENTRY(NS_FORMAT_NVdVnVmImm, 12) \ > + ENTRY(NS_FORMAT_NVdVnVmImmVectorShift, 13) \ > + ENTRY(NS_FORMAT_NVdVnVmImmVectorExtract, 14) \ > + ENTRY(NS_FORMAT_NVdVnVmImmMulScalar, 15) \ > + ENTRY(NS_FORMAT_VTBL, 16) > + > +// NEON instruction sub-format further classify the NEONFrm instruction. > +#define ENTRY(n, v) n = v, > +typedef enum { > + NS_FORMATS > + NS_FORMAT_NA > +} NSFormat; > +#undef ENTRY > + > +// Converts enum to const char*. > +static const inline char *stringForNSFormat(NSFormat form) { > +#define ENTRY(n, v) case n: return #n; > + switch(form) { > + NS_FORMATS > + case NS_FORMAT_NA: > + return "NA"; > + default: > + return ""; > + } > +#undef ENTRY > +} > + > +/// Expands on the enum definitions from ARMBaseInstrInfo.h. > +/// They are being used by the disassembler implementation. > +namespace ARMII { > + enum { > + NEONRegMask = 15, > + GPRRegMask = 15, > + NEON_RegRdShift = 12, > + NEON_D_BitShift = 22, > + NEON_RegRnShift = 16, > + NEON_N_BitShift = 7, > + NEON_RegRmShift = 0, > + NEON_M_BitShift = 5 > + }; > +} > + > +/// Utility function for extracting [From, To] bits from a uint32_t. > +static inline unsigned slice(uint32_t Bits, unsigned From, unsigned To) { > + assert(From < 32 && To < 32 && From >= To); > + return (Bits >> To) & ((1 << (From - To + 1)) - 1); > +} > + > +/// Utility function for setting [From, To] bits to Val for a uint32_t. > +static inline void setSlice(uint32_t &Bits, unsigned From, unsigned To, > + uint32_t Val) { > + assert(From < 32 && To < 32 && From >= To); > + uint32_t Mask = ((1 << (From - To + 1)) - 1); > + Bits &= ~(Mask << To); > + Bits |= (Val & Mask) << To; > +} > + > +/// Various utilities for checking the target specific flags. > + > +/// A unary data processing instruction doesn't have an Rn operand. > +static inline bool isUnaryDP(unsigned TSFlags) { > + return (TSFlags & ARMII::UnaryDP); > +} > + > +/// This four-bit field describes the addressing mode used. > +/// See also ARMBaseInstrInfo.h. > +static inline unsigned getAddrMode(unsigned TSFlags) { > + return (TSFlags & ARMII::AddrModeMask); > +} > + > +/// {IndexModePre, IndexModePost} > +/// Only valid for load and store ops. > +/// See also ARMBaseInstrInfo.h. > +static inline unsigned getIndexMode(unsigned TSFlags) { > + return (TSFlags & ARMII::IndexModeMask) >> ARMII::IndexModeShift; > +} > + > +/// Pre-/post-indexed operations define an extra $base_wb in the OutOperandList. > +static inline bool isPrePostLdSt(unsigned TSFlags) { > + return (TSFlags & ARMII::IndexModeMask) != 0; > +} > + > +/// AbstractARMMCBuilder - AbstractARMMCBuilder represents an interface of ARM > +/// MCInst builder that knows how to build up the MCOperand list. > +class AbstractARMMCBuilder { > +public: > + /// Build - Build the MCInst fully and return true. Return false if any > + /// failure occurs. > + virtual bool Build(MCInst &MI, uint32_t insn) { return false; } > +}; > + > +/// ARMDisassemblyAlgorithm - ARMDisassemblyAlgorithm represents an interface of > +/// ARM disassembly algorithm that relies on the entries of target operand info, > +/// among other things, to solve the problem of disassembling an ARM machine > +/// instruction. > +class ARMDisassemblyAlgorithm { > +public: > + /// Return true if this algorithm successfully disassembles the instruction. > + /// NumOpsAdded is updated to reflect the number of operands added by the > + /// algorithm. NumOpsAdded may be less than NumOps, in which case, there are > + /// operands unaccounted for which need to be dealt with by the API client. > + virtual bool Solve(MCInst& MI, unsigned Opcode, uint32_t insn, > + unsigned short NumOps, unsigned &NumOpsAdded) const > + = 0; > +}; > + > +/// ARMBasicMCBuilder - ARMBasicMCBuilder represents a concrete subclass of > +/// ARMAbstractMCBuilder. > +class ARMBasicMCBuilder : public AbstractARMMCBuilder { > + unsigned Opcode; > + ARMFormat Format; > + NSFormat NSF; > + unsigned short NumOps; > + const ARMDisassemblyAlgorithm &Algo; > + static unsigned ITCounter; // Possible values: 0, 1, 2, 3, 4. > + static unsigned ITState; // A2.5.2 Consists of IT[7:5] and IT[4:0] initially. > + > +public: > + ARMBasicMCBuilder(ARMBasicMCBuilder &MCB) : AbstractARMMCBuilder(), > + Opcode(MCB.Opcode), Format(MCB.Format), NSF(MCB.NSF), NumOps(MCB.NumOps), > + Algo(MCB.Algo) {} > + > + /// Opcode, Format, NSF, NumOperands, and Algo make an ARM Basic MCBuilder. > + ARMBasicMCBuilder(unsigned opc, ARMFormat format, NSFormat NSF, > + unsigned short num, const ARMDisassemblyAlgorithm &algo) > + : AbstractARMMCBuilder(), Opcode(opc), Format(format), NumOps(num), > + Algo(algo) {} > + > + /// TryPredicateAndSBitModifier - TryPredicateAndSBitModifier tries to process > + /// the possible Predicate and SBitModifier, to build the remaining MCOperand > + /// constituents. > + static bool TryPredicateAndSBitModifier(MCInst& MI, unsigned Opcode, > + uint32_t insn, unsigned short NumOpsRemaning); > + > + /// InITBlock - InITBlock returns true if we are inside an IT block. > + static bool InITBlock() { > + return ITCounter > 0; > + } > + > + /// Build - Build delegates to BuildIt to perform the heavy liftling. After > + /// that, it invokes RunBuildAfterHook where some housekeepings can be done. > + virtual bool Build(MCInst &MI, uint32_t insn) { > + bool Status = BuildIt(MI, insn); > + return RunBuildAfterHook(Status, MI, insn); > + } > + > + /// BuildIt - BuildIt performs the build step for this ARM Basic MC Builder. > + /// The general idea is to set the Opcode for the MCInst, followed by adding > + /// the appropriate MCOperands to the MCInst. ARM Basic MC Builder delegates > + /// to the Algo (ARM Disassemble Algorithm) object to perform Format-specific > + /// disassembly, followed by class method TryPredicateAndSBitModifier() to do > + /// PredicateOperand and OptionalDefOperand which follow the Dst/Src Operands. > + virtual bool BuildIt(MCInst &MI, uint32_t insn); > + > + /// RunBuildAfterHook - RunBuildAfterHook performs operations deemed necessary > + /// after BuildIt is finished. > + virtual bool RunBuildAfterHook(bool Status, MCInst &MI, uint32_t insn); > + > +private: > + /// Get condition of the current IT instruction. > + static unsigned GetITCond() { > + return slice(ITState, 7, 4); > + } > + > + /// Init ITState. > + static void InitITState(unsigned short bits7_0) { > + ITState = bits7_0; > + } > + > + /// Update ITState if necessary. > + static void UpdateITState() { > + assert(ITCounter); > + --ITCounter; > + if (ITCounter == 0) > + ITState = 0; > + else { > + unsigned short NewITState4_0 = slice(ITState, 4, 0) << 1; > + setSlice(ITState, 4, 0, NewITState4_0); > + } > + } > +}; > + > +/// ARMMCBuilderFactory - ARMMCBuilderFactory represents the factory class that > +/// vends out ARMAbstractMCBuilder instances through its class method. > +class ARMMCBuilderFactory { > +private: > + ARMMCBuilderFactory(); // DO NOT IMPLEMENT. > + > +public: > + /// CreateMCBuilder - Return an AbstractARMMCBuilder that can build up the MC > + /// infrastructure of an MCInst given the Opcode and Format of the instr. > + /// Return NULL if it fails to create/return a proper builder. API clients > + /// are responsible for freeing up of the allocated memory. Cacheing can be > + /// performed by the API clients to improve performance. > + static AbstractARMMCBuilder *CreateMCBuilder(unsigned Opcode, > + ARMFormat Format, NSFormat NSF); > +}; > + > +} // namespace llvm > + > +#endif > > Added: llvm/trunk/lib/Target/ARM/Disassembler/Makefile > URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Target/ARM/Disassembler/Makefile?rev=98637&view=auto > ============================================================================== > --- llvm/trunk/lib/Target/ARM/Disassembler/Makefile (added) > +++ llvm/trunk/lib/Target/ARM/Disassembler/Makefile Tue Mar 16 11:36:54 2010 > @@ -0,0 +1,17 @@ > +##===- lib/Target/ARM/Disassembler/Makefile ----------------*- Makefile -*-===## > +# > +# The LLVM Compiler Infrastructure > +# > +# This file is distributed under the University of Illinois Open Source > +# License. See LICENSE.TXT for details. > +# > +##===----------------------------------------------------------------------===## > + > +LEVEL = ../../../.. > +LIBRARYNAME = LLVMARMDisassembler > +CXXFLAGS = -fno-rtti > + > +# Hack: we need to include 'main' arm target directory to grab private headers > +CPPFLAGS = -I$(PROJ_OBJ_DIR)/.. -I$(PROJ_SRC_DIR)/.. > + > +include $(LEVEL)/Makefile.common > > Added: llvm/trunk/lib/Target/ARM/Disassembler/ThumbDisassemblerCore.cpp.inc > URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Target/ARM/Disassembler/ThumbDisassemblerCore.cpp.inc?rev=98637&view=auto > ============================================================================== > --- llvm/trunk/lib/Target/ARM/Disassembler/ThumbDisassemblerCore.cpp.inc (added) > +++ llvm/trunk/lib/Target/ARM/Disassembler/ThumbDisassemblerCore.cpp.inc Tue Mar 16 11:36:54 2010 > @@ -0,0 +1,2158 @@ > +//===- ThumbDisassemblerCore.cpp - ARM disassembler helpers ----*- C++ -*-===// > +// > +// The LLVM Compiler Infrastructure > +// > +// This file is distributed under the University of Illinois Open Source > +// License. See LICENSE.TXT for details. > +// > +//===----------------------------------------------------------------------===// > +// > +// This file is part of the ARM Disassembler. > +// It contains code for disassembling a Thumb instr. > +// > +//===----------------------------------------------------------------------===// > + > +/////////////////////////////// > +// // > +// Utility Functions // > +// // > +/////////////////////////////// > + > +// Utilities for 16-bit Thumb instructions. > +/* > +15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0 > + [ tRt ] > + [ tRm ] [ tRn ] [ tRd ] > + D [ Rm ] [ Rd ] > + > + [ imm3] > + [ imm5 ] > + i [ imm5 ] > + [ imm7 ] > + [ imm8 ] > + [ imm11 ] > + > + [ cond ] > +*/ > + > +static bool InITBlock() { > + return ARMBasicMCBuilder::InITBlock(); > +} > + > +// Extract tRt: Inst{10-8}. > +static inline unsigned getT1tRt(uint32_t insn) { > + return slice(insn, 10, 8); > +} > + > +// Extract tRm: Inst{8-6}. > +static inline unsigned getT1tRm(uint32_t insn) { > + return slice(insn, 8, 6); > +} > + > +// Extract tRn: Inst{5-3}. > +static inline unsigned getT1tRn(uint32_t insn) { > + return slice(insn, 5, 3); > +} > + > +// Extract tRd: Inst{2-0}. > +static inline unsigned getT1tRd(uint32_t insn) { > + return slice(insn, 2, 0); > +} > + > +// Extract [D:Rd]: Inst{7:2-0}. > +static inline unsigned getT1Rd(uint32_t insn) { > + return slice(insn, 7, 7) << 3 | slice(insn, 2, 0); > +} > + > +// Extract Rm: Inst{6-3}. > +static inline unsigned getT1Rm(uint32_t insn) { > + return slice(insn, 6, 3); > +} > + > +// Extract imm3: Inst{8-6}. > +static inline unsigned getT1Imm3(uint32_t insn) { > + return slice(insn, 8, 6); > +} > + > +// Extract imm5: Inst{10-6}. > +static inline unsigned getT1Imm5(uint32_t insn) { > + return slice(insn, 10, 6); > +} > + > +// Extract i:imm5: Inst{9:7-3}. > +static inline unsigned getT1Imm6(uint32_t insn) { > + return slice(insn, 9, 9) << 5 | slice(insn, 7, 3); > +} > + > +// Extract imm7: Inst{6-0}. > +static inline unsigned getT1Imm7(uint32_t insn) { > + return slice(insn, 6, 0); > +} > + > +// Extract imm8: Inst{7-0}. > +static inline unsigned getT1Imm8(uint32_t insn) { > + return slice(insn, 7, 0); > +} > + > +// Extract imm11: Inst{10-0}. > +static inline unsigned getT1Imm11(uint32_t insn) { > + return slice(insn, 10, 0); > +} > + > +// Extract cond: Inst{11-8}. > +static inline unsigned getT1Cond(uint32_t insn) { > + return slice(insn, 11, 8); > +} > + > +static inline bool IsGPR(unsigned RegClass) { > + return RegClass == ARM::GPRRegClassID; > +} > + > +// Utilities for 32-bit Thumb instructions. > + > +// Extract imm4: Inst{19-16}. > +static inline unsigned getImm4(uint32_t insn) { > + return slice(insn, 19, 16); > +} > + > +// Extract imm3: Inst{14-12}. > +static inline unsigned getImm3(uint32_t insn) { > + return slice(insn, 14, 12); > +} > + > +// Extract imm8: Inst{7-0}. > +static inline unsigned getImm8(uint32_t insn) { > + return slice(insn, 7, 0); > +} > + > +// A8.6.61 LDRB (immediate, Thumb) and friends > +// +/-: Inst{9} > +// imm8: Inst{7-0} > +static inline int decodeImm8(uint32_t insn) { > + int Offset = getImm8(insn); > + return slice(insn, 9, 9) ? Offset : -Offset; > +} > + > +// Extract imm12: Inst{11-0}. > +static inline unsigned getImm12(uint32_t insn) { > + return slice(insn, 11, 0); > +} > + > +// A8.6.63 LDRB (literal) and friends > +// +/-: Inst{23} > +// imm12: Inst{11-0} > +static inline int decodeImm12(uint32_t insn) { > + int Offset = getImm12(insn); > + return slice(insn, 23, 23) ? Offset : -Offset; > +} > + > +// Extract imm2: Inst{7-6}. > +static inline unsigned getImm2(uint32_t insn) { > + return slice(insn, 7, 6); > +} > + > +// For BFI, BFC, t2SBFX, and t2UBFX. > +// Extract lsb: Inst{14-12:7-6}. > +static inline unsigned getLsb(uint32_t insn) { > + return getImm3(insn) << 2 | getImm2(insn); > +} > + > +// For BFI and BFC. > +// Extract msb: Inst{4-0}. > +static inline unsigned getMsb(uint32_t insn) { > + return slice(insn, 4, 0); > +} > + > +// For t2SBFX and t2UBFX. > +// Extract widthminus1: Inst{4-0}. > +static inline unsigned getWidthMinus1(uint32_t insn) { > + return slice(insn, 4, 0); > +} > + > +// For t2ADDri12 and t2SUBri12. > +// imm12 = i:imm3:imm8; > +static inline unsigned getIImm3Imm8(uint32_t insn) { > + return slice(insn, 26, 26) << 11 | getImm3(insn) << 8 | getImm8(insn); > +} > + > +// For t2MOVi16 and t2MOVTi16. > +// imm16 = imm4:i:imm3:imm8; > +static inline unsigned getImm16(uint32_t insn) { > + return getImm4(insn) << 12 | slice(insn, 26, 26) << 11 | > + getImm3(insn) << 8 | getImm8(insn); > +} > + > +// Inst{5-4} encodes the shift type. > +static inline unsigned getShiftTypeBits(uint32_t insn) { > + return slice(insn, 5, 4); > +} > + > +// Inst{14-12}:Inst{7-6} encodes the imm5 shift amount. > +static inline unsigned getShiftAmtBits(uint32_t insn) { > + return getImm3(insn) << 2 | getImm2(insn); > +} > + > +// A8.6.17 BFC > +// Encoding T1 ARMv6T2, ARMv7 > +// LLVM-specific encoding for # and # > +static inline uint32_t getBitfieldInvMask(uint32_t insn) { > + uint32_t lsb = getImm3(insn) << 2 | getImm2(insn); > + uint32_t msb = getMsb(insn); > + uint32_t Val = 0; > + assert(lsb <= msb && "Encoding error: lsb > msb"); > + for (uint32_t i = lsb; i <= msb; ++i) > + Val |= (1 << i); > + return ~Val; > +} > + > +// A8.4 Shifts applied to a register > +// A8.4.1 Constant shifts > +// A8.4.3 Pseudocode details of instruction-specified shifts and rotates > +// > +// decodeImmShift() returns the shift amount and the the shift opcode. > +// Note that, as of Jan-06-2010, LLVM does not support rrx shifted operands yet. > +static inline unsigned decodeImmShift(unsigned bits2, unsigned imm5, > + ARM_AM::ShiftOpc &ShOp) { > + > + assert(imm5 < 32); > + switch (bits2) { > + default: assert(0 && "No such value"); > + case 0: > + ShOp = ARM_AM::lsl; > + return imm5; > + case 1: > + ShOp = ARM_AM::lsr; > + return (imm5 == 0 ? 32 : imm5); > + case 2: > + ShOp = ARM_AM::asr; > + return (imm5 == 0 ? 32 : imm5); > + case 3: > + ShOp = (imm5 == 0 ? ARM_AM::rrx : ARM_AM::ror); > + return (imm5 == 0 ? 1 : imm5); > + } > +} > + > +// A6.3.2 Modified immediate constants in Thumb instructions > +// > +// ThumbExpandImm() returns the modified immediate constant given an imm12 for > +// Thumb data-processing instructions with modified immediate. > +// See also A6.3.1 Data-processing (modified immediate). > +static inline unsigned ThumbExpandImm(unsigned imm12) { > + assert(imm12 <= 0xFFF); > + > + // If the leading two bits is 0b00, the modified immediate constant is > + // obtained by splatting the low 8 bits into the first byte, every other byte, > + // or every byte of a 32-bit value. > + // > + // Otherwise, a rotate right of '1':imm12<6:0> by the amount imm12<11:7> is > + // performed. > + > + if (slice(imm12, 11, 10) == 0) { > + unsigned short control = slice(imm12, 9, 8); > + unsigned imm8 = slice(imm12, 7, 0); > + switch (control) { > + default: > + assert(0 && "No such value"); > + return 0; > + case 0: > + return imm8; > + case 1: > + return imm8 << 16 | imm8; > + case 2: > + return imm8 << 24 | imm8 << 8; > + case 3: > + return imm8 << 24 | imm8 << 16 | imm8 << 8 | imm8; > + } > + } else { > + // A rotate is required. > + unsigned Val = 1 << 7 | slice(imm12, 6, 0); > + unsigned Amt = slice(imm12, 11, 7); > + return ARM_AM::rotr32(Val, Amt); > + } > +} > + > +static inline int decodeImm32_B_EncodingT3(uint32_t insn) { > + bool S = slice(insn, 26, 26); > + bool J1 = slice(insn, 13, 13); > + bool J2 = slice(insn, 11, 11); > + unsigned Imm21 = slice(insn, 21, 16) << 12 | slice(insn, 10, 0) << 1; > + if (S) Imm21 |= 1 << 20; > + if (J2) Imm21 |= 1 << 19; > + if (J1) Imm21 |= 1 << 18; > + > + return signextend(Imm21); > +} > + > +static inline int decodeImm32_B_EncodingT4(uint32_t insn) { > + unsigned S = slice(insn, 26, 26); > + bool I1 = slice(insn, 13, 13) == S; > + bool I2 = slice(insn, 11, 11) == S; > + unsigned Imm25 = slice(insn, 25, 16) << 12 | slice(insn, 10, 0) << 1; > + if (S) Imm25 |= 1 << 24; > + if (I1) Imm25 |= 1 << 23; > + if (I2) Imm25 |= 1 << 22; > + > + return signextend(Imm25); > +} > + > +static inline int decodeImm32_BL(uint32_t insn) { > + unsigned S = slice(insn, 26, 26); > + bool I1 = slice(insn, 13, 13) == S; > + bool I2 = slice(insn, 11, 11) == S; > + unsigned Imm25 = slice(insn, 25, 16) << 12 | slice(insn, 10, 0) << 1; > + if (S) Imm25 |= 1 << 24; > + if (I1) Imm25 |= 1 << 23; > + if (I2) Imm25 |= 1 << 22; > + > + return signextend(Imm25); > +} > + > +static inline int decodeImm32_BLX(uint32_t insn) { > + unsigned S = slice(insn, 26, 26); > + bool I1 = slice(insn, 13, 13) == S; > + bool I2 = slice(insn, 11, 11) == S; > + unsigned Imm25 = slice(insn, 25, 16) << 12 | slice(insn, 10, 1) << 2; > + if (S) Imm25 |= 1 << 24; > + if (I1) Imm25 |= 1 << 23; > + if (I2) Imm25 |= 1 << 22; > + > + return signextend(Imm25); > +} > + > +// See, for example, A8.6.221 SXTAB16. > +static inline unsigned decodeRotate(uint32_t insn) { > + unsigned rotate = slice(insn, 5, 4); > + return rotate << 3; > +} > + > +/////////////////////////////////////////////// > +// // > +// Thumb1 instruction disassembly functions. // > +// // > +/////////////////////////////////////////////// > + > +// See "Utilities for 16-bit Thumb instructions" for register naming convention. > + > +// A6.2.1 Shift (immediate), add, subtract, move, and compare > +// > +// shift immediate: tRd CPSR tRn imm5 > +// add/sub register: tRd CPSR tRn tRm > +// add/sub 3-bit immediate: tRd CPSR tRn imm3 > +// add/sub 8-bit immediate: tRt CPSR tRt(TIED_TO) imm8 > +// mov/cmp immediate: tRt [CPSR] imm8 (CPSR present for mov) > +// > +// Special case: > +// tMOVSr: tRd tRn > +static bool DisassembleThumb1General(MCInst &MI, unsigned Opcode, uint32_t insn, > + unsigned short NumOps, unsigned &NumOpsAdded) { > + > + const TargetOperandInfo *OpInfo = ARMInsts[Opcode].OpInfo; > + unsigned &OpIdx = NumOpsAdded; > + > + OpIdx = 0; > + > + assert(NumOps >= 2 && OpInfo[0].RegClass == ARM::tGPRRegClassID); > + > + bool Imm3 = (Opcode == ARM::tADDi3 || Opcode == ARM::tSUBi3); > + > + // Use Rt implies use imm8. > + bool UseRt = (Opcode == ARM::tADDi8 || Opcode == ARM::tSUBi8 || > + Opcode == ARM::tMOVi8 || Opcode == ARM::tCMPi8); > + > + // Add the destination operand. > + MI.addOperand(MCOperand::CreateReg( > + getRegisterEnum(ARM::tGPRRegClassID, > + UseRt ? getT1tRt(insn) : getT1tRd(insn)))); > + ++OpIdx; > + > + // Check whether the next operand to be added is a CCR Register. > + if (OpInfo[OpIdx].RegClass == ARM::CCRRegClassID) { > + assert(OpInfo[OpIdx].isOptionalDef()); > + MI.addOperand(MCOperand::CreateReg(InITBlock() ? 0 : ARM::CPSR)); > + ++OpIdx; > + } > + > + // Check whether the next operand to be added is a Thumb1 Register. > + assert(OpIdx < NumOps); > + if (OpInfo[OpIdx].RegClass == ARM::tGPRRegClassID) { > + // For UseRt, the reg operand is tied to the first reg operand. > + MI.addOperand(MCOperand::CreateReg( > + getRegisterEnum(ARM::tGPRRegClassID, > + UseRt ? getT1tRt(insn) : getT1tRn(insn)))); > + ++OpIdx; > + } > + > + // Special case for tMOVSr. > + if (OpIdx == NumOps) > + return true; > + > + // The next available operand is either a reg operand or an imm operand. > + if (OpInfo[OpIdx].RegClass == ARM::tGPRRegClassID) { > + // Three register operand instructions. > + MI.addOperand(MCOperand::CreateReg(getRegisterEnum(ARM::tGPRRegClassID, > + getT1tRm(insn)))); > + } else { > + assert(OpInfo[OpIdx].RegClass == 0 && > + !OpInfo[OpIdx].isPredicate() && !OpInfo[OpIdx].isOptionalDef()); > + MI.addOperand(MCOperand::CreateImm(UseRt ? getT1Imm8(insn) > + : (Imm3 ? getT1Imm3(insn) > + : getT1Imm5(insn)))); > + } > + ++OpIdx; > + > + return true; > +} > + > +// A6.2.2 Data-processing > +// > +// tCMPr, tTST, tCMN: tRd tRn > +// tMVN, tRSB: tRd CPSR tRn > +// Others: tRd CPSR tRd(TIED_TO) tRn > +static bool DisassembleThumb1DP(MCInst &MI, unsigned Opcode, uint32_t insn, > + unsigned short NumOps, unsigned &NumOpsAdded) { > + > + const TargetInstrDesc &TID = ARMInsts[Opcode]; > + const TargetOperandInfo *OpInfo = TID.OpInfo; > + unsigned &OpIdx = NumOpsAdded; > + > + OpIdx = 0; > + > + assert(NumOps >= 2 && OpInfo[0].RegClass == ARM::tGPRRegClassID && > + (OpInfo[1].RegClass == ARM::CCRRegClassID > + || OpInfo[1].RegClass == ARM::tGPRRegClassID)); > + > + // Add the destination operand. > + MI.addOperand(MCOperand::CreateReg(getRegisterEnum(ARM::tGPRRegClassID, > + getT1tRd(insn)))); > + ++OpIdx; > + > + // Check whether the next operand to be added is a CCR Register. > + if (OpInfo[OpIdx].RegClass == ARM::CCRRegClassID) { > + assert(OpInfo[OpIdx].isOptionalDef()); > + MI.addOperand(MCOperand::CreateReg(InITBlock() ? 0 : ARM::CPSR)); > + ++OpIdx; > + } > + > + // We have either { tRd(TIED_TO), tRn } or { tRn } remaining. > + // Process the TIED_TO operand first. > + > + assert(OpIdx < NumOps && OpInfo[OpIdx].RegClass == ARM::tGPRRegClassID); > + int Idx; > + if ((Idx = TID.getOperandConstraint(OpIdx, TOI::TIED_TO)) != -1) { > + // The reg operand is tied to the first reg operand. > + MI.addOperand(MI.getOperand(Idx)); > + ++OpIdx; > + } > + > + // Process possible next reg operand. > + if (OpIdx < NumOps && OpInfo[OpIdx].RegClass == ARM::tGPRRegClassID) { > + // Add tRn operand. > + MI.addOperand(MCOperand::CreateReg(getRegisterEnum(ARM::tGPRRegClassID, > + getT1tRn(insn)))); > + ++OpIdx; > + } > + > + return true; > +} > + > +// A6.2.3 Special data instructions and branch and exchange > +// > +// tADDhirr: Rd Rd(TIED_TO) Rm > +// tCMPhir: Rd Rm > +// tMOVr, tMOVgpr2gpr, tMOVgpr2tgpr, tMOVtgpr2gpr: Rd|tRd Rm|tRn > +// tBX_RET: 0 operand > +// tBX_RET_vararg: Rm > +// tBLXr_r9: Rm > +static bool DisassembleThumb1Special(MCInst &MI, unsigned Opcode, uint32_t insn, > + unsigned short NumOps, unsigned &NumOpsAdded) { > + > + // tBX_RET has 0 operand. > + if (NumOps == 0) > + return true; > + > + // BX/BLX has 1 reg operand: Rm. > + if (NumOps == 1) { > + MI.addOperand(MCOperand::CreateReg(getRegisterEnum(ARM::GPRRegClassID, > + getT1Rm(insn)))); > + NumOpsAdded = 1; > + return true; > + } > + > + const TargetInstrDesc &TID = ARMInsts[Opcode]; > + const TargetOperandInfo *OpInfo = TID.OpInfo; > + unsigned &OpIdx = NumOpsAdded; > + > + OpIdx = 0; > + > + // Add the destination operand. > + unsigned RegClass = OpInfo[OpIdx].RegClass; > + MI.addOperand(MCOperand::CreateReg( > + getRegisterEnum(RegClass, > + IsGPR(RegClass) ? getT1Rd(insn) > + : getT1tRd(insn)))); > + ++OpIdx; > + > + // We have either { Rd(TIED_TO), Rm } or { Rm|tRn } remaining. > + // Process the TIED_TO operand first. > + > + assert(OpIdx < NumOps); > + int Idx; > + if ((Idx = TID.getOperandConstraint(OpIdx, TOI::TIED_TO)) != -1) { > + // The reg operand is tied to the first reg operand. > + MI.addOperand(MI.getOperand(Idx)); > + ++OpIdx; > + } > + > + // The next reg operand is either Rm or tRn. > + assert(OpIdx < NumOps); > + RegClass = OpInfo[OpIdx].RegClass; > + MI.addOperand(MCOperand::CreateReg( > + getRegisterEnum(RegClass, > + IsGPR(RegClass) ? getT1Rm(insn) > + : getT1tRn(insn)))); > + ++OpIdx; > + > + return true; > +} > + > +// A8.6.59 LDR (literal) > +// > +// tLDRpci: tRt imm8*4 > +static bool DisassembleThumb1LdPC(MCInst &MI, unsigned Opcode, uint32_t insn, > + unsigned short NumOps, unsigned &NumOpsAdded) { > + > + const TargetOperandInfo *OpInfo = ARMInsts[Opcode].OpInfo; > + > + assert(NumOps >= 2 && OpInfo[0].RegClass == ARM::tGPRRegClassID && > + (OpInfo[1].RegClass == 0 && > + !OpInfo[1].isPredicate() && > + !OpInfo[1].isOptionalDef())); > + > + // Add the destination operand. > + MI.addOperand(MCOperand::CreateReg(getRegisterEnum(ARM::tGPRRegClassID, > + getT1tRt(insn)))); > + > + // And the (imm8 << 2) operand. > + MI.addOperand(MCOperand::CreateImm(getT1Imm8(insn) << 2)); > + > + NumOpsAdded = 2; > + > + return true; > +} > + > +// Thumb specific addressing modes (see ARMInstrThumb.td): > +// > +// t_addrmode_rr := reg + reg > +// > +// t_addrmode_s4 := reg + reg > +// reg + imm5 * 4 > +// > +// t_addrmode_s2 := reg + reg > +// reg + imm5 * 2 > +// > +// t_addrmode_s1 := reg + reg > +// reg + imm5 > +// > +// t_addrmode_sp := sp + imm8 * 4 > +// > + > +// A6.2.4 Load/store single data item > +// > +// Load/Store Register (reg|imm): tRd tRn imm5 tRm > +// Load Register Signed Byte|Halfword: tRd tRn tRm > +static bool DisassembleThumb1LdSt(unsigned opA, MCInst &MI, unsigned Opcode, > + uint32_t insn, unsigned short NumOps, unsigned &NumOpsAdded) { > + > + const TargetInstrDesc &TID = ARMInsts[Opcode]; > + const TargetOperandInfo *OpInfo = TID.OpInfo; > + unsigned &OpIdx = NumOpsAdded; > + > + // Table A6-5 16-bit Thumb Load/store instructions > + // opA = 0b0101 for STR/LDR (register) and friends. > + // Otherwise, we have STR/LDR (immediate) and friends. > + bool Imm5 = (opA != 5); > + > + assert(NumOps >= 2 > + && OpInfo[0].RegClass == ARM::tGPRRegClassID > + && OpInfo[1].RegClass == ARM::tGPRRegClassID); > + > + // Add the destination reg and the base reg. > + MI.addOperand(MCOperand::CreateReg(getRegisterEnum(ARM::tGPRRegClassID, > + getT1tRd(insn)))); > + MI.addOperand(MCOperand::CreateReg(getRegisterEnum(ARM::tGPRRegClassID, > + getT1tRn(insn)))); > + OpIdx = 2; > + > + // We have either { imm5, tRm } or { tRm } remaining. > + // Process the imm5 first. Note that STR/LDR (register) should skip the imm5 > + // offset operand for t_addrmode_s[1|2|4]. > + > + assert(OpIdx < NumOps); > + > + if (OpInfo[OpIdx].RegClass == 0 && !OpInfo[OpIdx].isPredicate() && > + !OpInfo[OpIdx].isOptionalDef()) { > + > + MI.addOperand(MCOperand::CreateImm(Imm5 ? getT1Imm5(insn) : 0)); > + ++OpIdx; > + } > + > + // The next reg operand is tRm, the offset. > + assert(OpIdx < NumOps && OpInfo[OpIdx].RegClass == ARM::tGPRRegClassID); > + MI.addOperand(MCOperand::CreateReg(Imm5 ? 0 > + : getRegisterEnum(ARM::tGPRRegClassID, > + getT1tRm(insn)))); > + ++OpIdx; > + > + return true; > +} > + > +// A6.2.4 Load/store single data item > +// > +// Load/Store Register SP relative: tRt ARM::SP imm8 > +static bool DisassembleThumb1LdStSP(MCInst &MI, unsigned Opcode, uint32_t insn, > + unsigned short NumOps, unsigned &NumOpsAdded) { > + > + assert(Opcode == ARM::tLDRspi || Opcode == ARM::tSTRspi); > + > + const TargetOperandInfo *OpInfo = ARMInsts[Opcode].OpInfo; > + > + assert(NumOps >= 3 && > + OpInfo[0].RegClass == ARM::tGPRRegClassID && > + OpInfo[1].RegClass == ARM::GPRRegClassID && > + (OpInfo[2].RegClass == 0 && > + !OpInfo[2].isPredicate() && > + !OpInfo[2].isOptionalDef())); > + > + MI.addOperand(MCOperand::CreateReg(getRegisterEnum(ARM::tGPRRegClassID, > + getT1tRt(insn)))); > + MI.addOperand(MCOperand::CreateReg(ARM::SP)); > + MI.addOperand(MCOperand::CreateImm(getT1Imm8(insn))); > + NumOpsAdded = 3; > + return true; > +} > + > +// Table A6-1 16-bit Thumb instruction encoding > +// A8.6.10 ADR > +// > +// tADDrPCi: tRt imm8 > +static bool DisassembleThumb1AddPCi(MCInst &MI, unsigned Opcode, uint32_t insn, > + unsigned short NumOps, unsigned &NumOpsAdded) { > + > + assert(Opcode == ARM::tADDrPCi); > + > + const TargetOperandInfo *OpInfo = ARMInsts[Opcode].OpInfo; > + > + assert(NumOps >= 2 && OpInfo[0].RegClass == ARM::tGPRRegClassID && > + (OpInfo[1].RegClass == 0 && > + !OpInfo[1].isPredicate() && > + !OpInfo[1].isOptionalDef())); > + > + MI.addOperand(MCOperand::CreateReg(getRegisterEnum(ARM::tGPRRegClassID, > + getT1tRt(insn)))); > + MI.addOperand(MCOperand::CreateImm(getT1Imm8(insn))); > + NumOpsAdded = 2; > + return true; > +} > + > +// Table A6-1 16-bit Thumb instruction encoding > +// A8.6.8 ADD (SP plus immediate) > +// > +// tADDrSPi: tRt ARM::SP imm8 > +static bool DisassembleThumb1AddSPi(MCInst &MI, unsigned Opcode, uint32_t insn, > + unsigned short NumOps, unsigned &NumOpsAdded) { > + > + assert(Opcode == ARM::tADDrSPi); > + > + const TargetOperandInfo *OpInfo = ARMInsts[Opcode].OpInfo; > + > + assert(NumOps >= 3 && > + OpInfo[0].RegClass == ARM::tGPRRegClassID && > + OpInfo[1].RegClass == ARM::GPRRegClassID && > + (OpInfo[2].RegClass == 0 && > + !OpInfo[2].isPredicate() && > + !OpInfo[2].isOptionalDef())); > + > + MI.addOperand(MCOperand::CreateReg(getRegisterEnum(ARM::tGPRRegClassID, > + getT1tRt(insn)))); > + MI.addOperand(MCOperand::CreateReg(ARM::SP)); > + MI.addOperand(MCOperand::CreateImm(getT1Imm8(insn))); > + NumOpsAdded = 3; > + return true; > +} > + > +// tPUSH, tPOP: Pred-Imm Pred-CCR register_list > +// > +// where register_list = low registers + [lr] for PUSH or > +// low registers + [pc] for POP > +// > +// "low registers" is specified by Inst{7-0} > +// lr|pc is specified by Inst{8} > +static bool DisassembleThumb1PushPop(MCInst &MI, unsigned Opcode, uint32_t insn, > + unsigned short NumOps, unsigned &NumOpsAdded) { > + > + assert(Opcode == ARM::tPUSH || Opcode == ARM::tPOP); > + > + unsigned &OpIdx = NumOpsAdded; > + > + // Handling the two predicate operands before the reglist. > + MI.addOperand(MCOperand::CreateImm(ARMCC::AL)); > + MI.addOperand(MCOperand::CreateReg(ARM::CPSR)); > + OpIdx = 2; > + > + // Fill the variadic part of reglist. > + unsigned RegListBits = slice(insn, 8, 8) << (Opcode == ARM::tPUSH ? 14 : 15) > + | slice(insn, 7, 0); > + for (unsigned i = 0; i < 16; ++i) { > + if ((RegListBits >> i) & 1) { > + MI.addOperand(MCOperand::CreateReg(getRegisterEnum(ARM::GPRRegClassID, > + i))); > + ++OpIdx; > + } > + } > + > + return true; > +} > + > +// A6.2.5 Miscellaneous 16-bit instructions > +// Delegate to DisassembleThumb1PushPop() for tPUSH & tPOP. > +// > +// tADDspi, tSUBspi: ARM::SP ARM::SP(TIED_TO) imm7 > +// t2IT: firstcond=Inst{7-4} mask=Inst{3-0} > +// tCBNZ, tCBZ: tRd imm6*2 > +// tBKPT: imm8 > +// tNOP, tSEV, tYIELD, tWFE, tWFI: > +// no operand (except predicate pair) > +// tSETENDBE, tSETENDLE, : > +// no operand > +// Others: tRd tRn > +static bool DisassembleThumb1Misc(MCInst &MI, unsigned Opcode, uint32_t insn, > + unsigned short NumOps, unsigned &NumOpsAdded) { > + > + if (NumOps == 0) > + return true; > + > + if (Opcode == ARM::tPUSH || Opcode == ARM::tPOP) > + return DisassembleThumb1PushPop(MI, Opcode, insn, NumOps, NumOpsAdded); > + > + const TargetOperandInfo *OpInfo = ARMInsts[Opcode].OpInfo; > + > + // Predicate operands are handled elsewhere. > + if (NumOps == 2 && > + OpInfo[0].isPredicate() && OpInfo[1].isPredicate() && > + OpInfo[0].RegClass == 0 && OpInfo[1].RegClass == ARM::CCRRegClassID) { > + return true; > + } > + > + if (Opcode == ARM::tADDspi || Opcode == ARM::tSUBspi) { > + // Special case handling for tADDspi and tSUBspi. > + // A8.6.8 ADD (SP plus immediate) & A8.6.215 SUB (SP minus immediate) > + MI.addOperand(MCOperand::CreateReg(ARM::SP)); > + MI.addOperand(MCOperand::CreateReg(ARM::SP)); > + MI.addOperand(MCOperand::CreateImm(getT1Imm7(insn))); > + NumOpsAdded = 3; > + return true; > + } > + > + if (Opcode == ARM::t2IT) { > + // Special case handling for If-Then. > + // A8.6.50 IT > + // Tag the (firstcond[0] bit << 4) along with mask. > + > + // firstcond > + MI.addOperand(MCOperand::CreateImm(slice(insn, 7, 4))); > + > + // firstcond[0] and mask > + MI.addOperand(MCOperand::CreateImm(slice(insn, 4, 0))); > + NumOpsAdded = 2; > + return true; > + } > + > + if (Opcode == ARM::tBKPT) { > + MI.addOperand(MCOperand::CreateImm(getT1Imm8(insn))); // breakpoint value > + NumOpsAdded = 1; > + return true; > + } > + > + // CPS has a singleton $opt operand that contains the following information: > + // opt{4-0} = don't care > + // opt{5} = 0 (false) > + // opt{8-6} = AIF from Inst{2-0} > + // opt{10-9} = 1:imod from Inst{4} with 0b10 as enable and 0b11 as disable > + if (Opcode == ARM::tCPS) { > + unsigned Option = slice(insn, 2, 0) << 6 | slice(insn, 4, 4) << 9 | 1 << 10; > + MI.addOperand(MCOperand::CreateImm(Option)); > + NumOpsAdded = 1; > + return true; > + } > + > + assert(NumOps >= 2 && OpInfo[0].RegClass == ARM::tGPRRegClassID && > + (OpInfo[1].RegClass==0 || OpInfo[1].RegClass==ARM::tGPRRegClassID)); > + > + // Add the destination operand. > + MI.addOperand(MCOperand::CreateReg(getRegisterEnum(ARM::tGPRRegClassID, > + getT1tRd(insn)))); > + > + if (OpInfo[1].RegClass == ARM::tGPRRegClassID) { > + // Two register instructions. > + MI.addOperand(MCOperand::CreateReg(getRegisterEnum(ARM::tGPRRegClassID, > + getT1tRn(insn)))); > + } else { > + // CBNZ, CBZ > + assert(Opcode == ARM::tCBNZ || Opcode == ARM::tCBZ); > + MI.addOperand(MCOperand::CreateImm(getT1Imm6(insn) * 2)); > + } > + > + NumOpsAdded = 2; > + > + return true; > +} > + > +// A8.6.53 LDM / LDMIA > +// A8.6.189 STM / STMIA > +// > +// tRt AM4ModeImm Pred-Imm Pred-CCR register_list > +static bool DisassembleThumb1LdStMul(bool Ld, MCInst &MI, unsigned Opcode, > + uint32_t insn, unsigned short NumOps, unsigned &NumOpsAdded) { > + > + assert(Opcode == ARM::tLDM || Opcode == ARM::tSTM_UPD); > + > + unsigned &OpIdx = NumOpsAdded; > + > + unsigned tRt = getT1tRt(insn); > + unsigned RegListBits = slice(insn, 7, 0); > + > + OpIdx = 0; > + > + // For STM, WB is always true. > + if (Opcode == ARM::tSTM_UPD) { > + MI.addOperand(MCOperand::CreateReg(getRegisterEnum(ARM::GPRRegClassID, > + tRt))); > + ++OpIdx; > + } > + > + MI.addOperand(MCOperand::CreateReg(getRegisterEnum(ARM::GPRRegClassID, > + tRt))); > + ++OpIdx; > + > + // A8.6.53 LDM / LDMIA / LDMFD - Encoding T1 > + // WB is true if tRt is not specified as a member of the register list. > + // For STM, WB is always true. > + bool WB = Ld ? ((RegListBits >> tRt) & 1) == 0 : true; > + MI.addOperand(MCOperand::CreateImm(ARM_AM::getAM4ModeImm(ARM_AM::ia, WB))); > + ++OpIdx; > + > + // Handling the two predicate operands before the reglist. > + MI.addOperand(MCOperand::CreateImm(ARMCC::AL)); > + MI.addOperand(MCOperand::CreateReg(ARM::CPSR)); > + OpIdx += 2; > + > + // Fill the variadic part of reglist. > + for (unsigned i = 0; i < 8; ++i) { > + if ((RegListBits >> i) & 1) { > + MI.addOperand(MCOperand::CreateReg(getRegisterEnum(ARM::tGPRRegClassID, > + i))); > + ++OpIdx; > + } > + } > + > + return true; > +} > + > +static bool DisassembleThumb1LdMul(MCInst &MI, unsigned Opcode, uint32_t insn, > + unsigned short NumOps, unsigned &NumOpsAdded) { > + return DisassembleThumb1LdStMul(true, MI, Opcode, insn, NumOps, NumOpsAdded); > +} > + > +static bool DisassembleThumb1StMul(MCInst &MI, unsigned Opcode, uint32_t insn, > + unsigned short NumOps, unsigned &NumOpsAdded) { > + return DisassembleThumb1LdStMul(false, MI, Opcode, insn, NumOps, NumOpsAdded); > +} > + > +// A8.6.16 B Encoding T1 > +// cond = Inst{11-8} & imm8 = Inst{7-0} > +// imm32 = SignExtend(imm8:'0', 32) > +// > +// tBcc: offset Pred-Imm Pred-CCR > +// tSVC: imm8 Pred-Imm Pred-CCR > +// tTRAP: 0 operand (early return) > +static bool DisassembleThumb1CondBr(MCInst &MI, unsigned Opcode, uint32_t insn, > + unsigned short NumOps, unsigned &NumOpsAdded) { > + > + if (Opcode == ARM::tTRAP) > + return true; > + > + const TargetOperandInfo *OpInfo = ARMInsts[Opcode].OpInfo; > + assert(NumOps == 3 && OpInfo[0].RegClass == 0 && > + OpInfo[1].isPredicate() && OpInfo[2].RegClass == ARM::CCRRegClassID); > + > + unsigned Imm8 = getT1Imm8(insn); > + MI.addOperand(MCOperand::CreateImm( > + Opcode == ARM::tBcc ? signextend(Imm8 << 1) + 4 > + : (int)Imm8)); > + > + // Predicate operands by ARMBasicMCBuilder::TryPredicateAndSBitModifier(). > + NumOpsAdded = 1; > + > + return true; > +} > + > +// A8.6.16 B Encoding T2 > +// imm11 = Inst{10-0} > +// imm32 = SignExtend(imm11:'0', 32) > +// > +// tB: offset > +static bool DisassembleThumb1Br(MCInst &MI, unsigned Opcode, uint32_t insn, > + unsigned short NumOps, unsigned &NumOpsAdded) { > + > + const TargetOperandInfo *OpInfo = ARMInsts[Opcode].OpInfo; > + assert(NumOps == 1 && OpInfo[0].RegClass == 0); > + > + unsigned Imm11 = getT1Imm11(insn); > + > + // When executing a Thumb instruction, PC reads as the address of the current > + // instruction plus 4. The assembler subtracts 4 from the difference between > + // the branch instruction and the target address, disassembler has to add 4 to > + // to compensate. > + MI.addOperand(MCOperand::CreateImm( > + signextend(Imm11 << 1) + 4)); > + > + NumOpsAdded = 1; > + > + return true; > + > +} > + > +// See A6.2 16-bit Thumb instruction encoding for instruction classes > +// corresponding to op. > +// > +// Table A6-1 16-bit Thumb instruction encoding (abridged) > +// op Instruction or instruction class > +// ------ -------------------------------------------------------------------- > +// 00xxxx Shift (immediate), add, subtract, move, and compare on page A6-7 > +// 010000 Data-processing on page A6-8 > +// 010001 Special data instructions and branch and exchange on page A6-9 > +// 01001x Load from Literal Pool, see LDR (literal) on page A8-122 > +// 0101xx Load/store single data item on page A6-10 > +// 011xxx > +// 100xxx > +// 10100x Generate PC-relative address, see ADR on page A8-32 > +// 10101x Generate SP-relative address, see ADD (SP plus immediate) on page A8-28 > +// 1011xx Miscellaneous 16-bit instructions on page A6-11 > +// 11000x Store multiple registers, see STM / STMIA / STMEA on page A8-374 > +// 11001x Load multiple registers, see LDM / LDMIA / LDMFD on page A8-110 a > +// 1101xx Conditional branch, and Supervisor Call on page A6-13 > +// 11100x Unconditional Branch, see B on page A8-44 > +// > +static bool DisassembleThumb1(uint16_t op, > + MCInst &MI, unsigned Opcode, uint32_t insn, > + unsigned short NumOps, unsigned &NumOpsAdded) { > + > + unsigned op1 = slice(op, 5, 4); > + unsigned op2 = slice(op, 3, 2); > + unsigned op3 = slice(op, 1, 0); > + unsigned opA = slice(op, 5, 2); > + switch (op1) { > + case 0: > + // A6.2.1 Shift (immediate), add, subtract, move, and compare > + return DisassembleThumb1General(MI, Opcode, insn, NumOps, NumOpsAdded); > + case 1: > + switch (op2) { > + case 0: > + switch (op3) { > + case 0: > + // A6.2.2 Data-processing > + return DisassembleThumb1DP(MI, Opcode, insn, NumOps, NumOpsAdded); > + case 1: > + // A6.2.3 Special data instructions and branch and exchange > + return DisassembleThumb1Special(MI, Opcode, insn, NumOps, NumOpsAdded); > + default: > + // A8.6.59 LDR (literal) > + return DisassembleThumb1LdPC(MI, Opcode, insn, NumOps, NumOpsAdded); > + } > + break; > + default: > + // A6.2.4 Load/store single data item > + return DisassembleThumb1LdSt(opA, MI, Opcode, insn, NumOps, NumOpsAdded); > + break; > + } > + break; > + case 2: > + switch (op2) { > + case 0: > + // A6.2.4 Load/store single data item > + return DisassembleThumb1LdSt(opA, MI, Opcode, insn, NumOps, NumOpsAdded); > + case 1: > + // A6.2.4 Load/store single data item > + return DisassembleThumb1LdStSP(MI, Opcode, insn, NumOps, NumOpsAdded); > + case 2: > + if (op3 <= 1) { > + // A8.6.10 ADR > + return DisassembleThumb1AddPCi(MI, Opcode, insn, NumOps, NumOpsAdded); > + } else { > + // A8.6.8 ADD (SP plus immediate) > + return DisassembleThumb1AddSPi(MI, Opcode, insn, NumOps, NumOpsAdded); > + } > + default: > + // A6.2.5 Miscellaneous 16-bit instructions > + return DisassembleThumb1Misc(MI, Opcode, insn, NumOps, NumOpsAdded); > + } > + break; > + case 3: > + switch (op2) { > + case 0: > + if (op3 <= 1) { > + // A8.6.189 STM / STMIA / STMEA > + return DisassembleThumb1StMul(MI, Opcode, insn, NumOps, NumOpsAdded); > + } else { > + // A8.6.53 LDM / LDMIA / LDMFD > + return DisassembleThumb1LdMul(MI, Opcode, insn, NumOps, NumOpsAdded); > + } > + case 1: > + // A6.2.6 Conditional branch, and Supervisor Call > + return DisassembleThumb1CondBr(MI, Opcode, insn, NumOps, NumOpsAdded); > + case 2: > + // Unconditional Branch, see B on page A8-44 > + return DisassembleThumb1Br(MI, Opcode, insn, NumOps, NumOpsAdded); > + default: > + assert(0 && "Unreachable code"); > + break; > + } > + break; > + default: > + assert(0 && "Unreachable code"); > + break; > + } > + > + return false; > +} > + > +/////////////////////////////////////////////// > +// // > +// Thumb2 instruction disassembly functions. // > +// // > +/////////////////////////////////////////////// > + > +/////////////////////////////////////////////////////////// > +// // > +// Note: the register naming follows the ARM convention! // > +// // > +/////////////////////////////////////////////////////////// > + > +static inline bool Thumb2SRSOpcode(unsigned Opcode) { > + switch (Opcode) { > + default: > + return false; > + case ARM::t2SRSDBW: case ARM::t2SRSDB: > + case ARM::t2SRSIAW: case ARM::t2SRSIA: > + return true; > + } > +} > + > +static inline bool Thumb2RFEOpcode(unsigned Opcode) { > + switch (Opcode) { > + default: > + return false; > + case ARM::t2RFEDBW: case ARM::t2RFEDB: > + case ARM::t2RFEIAW: case ARM::t2RFEIA: > + return true; > + } > +} > + > +// t2SRS[IA|DB]W/t2SRS[IA|DB]: mode_imm = Inst{4-0} > +static bool DisassembleThumb2SRS(MCInst &MI, unsigned Opcode, uint32_t insn, > + unsigned short NumOps, unsigned &NumOpsAdded) { > + MI.addOperand(MCOperand::CreateImm(slice(insn, 4, 0))); > + NumOpsAdded = 1; > + return true; > +} > + > +// t2RFE[IA|DB]W/t2RFE[IA|DB]: Rn > +static bool DisassembleThumb2RFE(MCInst &MI, unsigned Opcode, uint32_t insn, > + unsigned short NumOps, unsigned &NumOpsAdded) { > + MI.addOperand(MCOperand::CreateReg(getRegisterEnum(ARM::GPRRegClassID, > + decodeRn(insn)))); > + NumOpsAdded = 1; > + return true; > +} > + > +static bool DisassembleThumb2LdStMul(MCInst &MI, unsigned Opcode, uint32_t insn, > + unsigned short NumOps, unsigned &NumOpsAdded) { > + > + if (Thumb2SRSOpcode(Opcode)) > + return DisassembleThumb2SRS(MI, Opcode, insn, NumOps, NumOpsAdded); > + > + if (Thumb2RFEOpcode(Opcode)) > + return DisassembleThumb2RFE(MI, Opcode, insn, NumOps, NumOpsAdded); > + > + assert(Opcode == ARM::t2LDM || Opcode == ARM::t2LDM_UPD || > + Opcode == ARM::t2STM || Opcode == ARM::t2STM_UPD); > + assert(NumOps >= 5 && "Thumb2 LdStMul expects NumOps of 5"); > + > + unsigned &OpIdx = NumOpsAdded; > + > + OpIdx = 0; > + > + unsigned Base = getRegisterEnum(ARM::GPRRegClassID, decodeRn(insn)); > + > + // Writeback to base. > + if (Opcode == ARM::t2LDM_UPD || Opcode == ARM::t2STM_UPD) { > + MI.addOperand(MCOperand::CreateReg(Base)); > + ++OpIdx; > + } > + > + MI.addOperand(MCOperand::CreateReg(Base)); > + ++OpIdx; > + > + ARM_AM::AMSubMode SubMode = getAMSubModeForBits(getPUBits(insn)); > + bool WB = getWBit(insn) == 1; > + MI.addOperand(MCOperand::CreateImm(ARM_AM::getAM4ModeImm(SubMode, WB))); > + ++OpIdx; > + > + // Handling the two predicate operands before the reglist. > + MI.addOperand(MCOperand::CreateImm(ARMCC::AL)); > + MI.addOperand(MCOperand::CreateReg(ARM::CPSR)); > + OpIdx += 2; > + > + // Fill the variadic part of reglist. > + unsigned RegListBits = insn & ((1 << 16) - 1); > + for (unsigned i = 0; i < 16; ++i) { > + if ((RegListBits >> i) & 1) { > + MI.addOperand(MCOperand::CreateReg(getRegisterEnum(ARM::GPRRegClassID, > + i))); > + ++OpIdx; > + } > + } > + > + return true; > +} > + > +// t2LDREX: Rd Rn > +// t2LDREXD: Rd Rs Rn > +// t2LDREXB, t2LDREXH: Rd Rn > +// t2STREX: Rs Rd Rn > +// t2STREXD: Rm Rd Rs Rn > +// t2STREXB, t2STREXH: Rm Rd Rn > +static bool DisassembleThumb2LdStEx(MCInst &MI, unsigned Opcode, uint32_t insn, > + unsigned short NumOps, unsigned &NumOpsAdded) { > + > + const TargetOperandInfo *OpInfo = ARMInsts[Opcode].OpInfo; > + unsigned &OpIdx = NumOpsAdded; > + > + OpIdx = 0; > + > + assert(NumOps >= 2 > + && OpInfo[0].RegClass == ARM::GPRRegClassID > + && OpInfo[1].RegClass == ARM::GPRRegClassID); > + > + bool isStore = (ARM::t2STREX <= Opcode && Opcode <= ARM::t2STREXH); > + bool isSW = (Opcode == ARM::t2LDREX || Opcode == ARM::t2STREX); > + bool isDW = (Opcode == ARM::t2LDREXD || Opcode == ARM::t2STREXD); > + > + // Add the destination operand for store. > + if (isStore) { > + MI.addOperand(MCOperand::CreateReg( > + getRegisterEnum(ARM::GPRRegClassID, > + isSW ? decodeRs(insn) : decodeRm(insn)))); > + ++OpIdx; > + } > + > + // Source operand for store and destination operand for load. > + MI.addOperand(MCOperand::CreateReg(getRegisterEnum(ARM::GPRRegClassID, > + decodeRd(insn)))); > + ++OpIdx; > + > + // Thumb2 doubleword complication: with an extra source/destination operand. > + if (isDW) { > + MI.addOperand(MCOperand::CreateReg(getRegisterEnum(ARM::GPRRegClassID, > + decodeRs(insn)))); > + ++OpIdx; > + } > + > + // Finally add the pointer operand. > + MI.addOperand(MCOperand::CreateReg(getRegisterEnum(ARM::GPRRegClassID, > + decodeRn(insn)))); > + ++OpIdx; > + > + return true; > +} > + > +// LLVM, as of Jan-05-2010, does not output , i.e., Rs, in the asm. > +// Whereas the ARM Arch. Manual does not require that t2 = t+1 like in ARM ISA. > +// > +// t2LDRDi8: Rd Rs Rn imm8s4 (offset mode) > +// t2LDRDpci: Rd Rs imm8s4 (Not decoded, prefer the generic t2LDRDi8 version) > +// t2STRDi8: Rd Rs Rn imm8s4 (offset mode) > +// > +// Ditto for t2LDRD_PRE, t2LDRD_POST, t2STRD_PRE, t2STRD_POST, which are for > +// disassembly only and do not have a tied_to writeback base register operand. > +static bool DisassembleThumb2LdStDual(MCInst &MI, unsigned Opcode, > + uint32_t insn, unsigned short NumOps, unsigned &NumOpsAdded) { > + > + const TargetOperandInfo *OpInfo = ARMInsts[Opcode].OpInfo; > + > + assert(NumOps >= 4 > + && OpInfo[0].RegClass == ARM::GPRRegClassID > + && OpInfo[1].RegClass == ARM::GPRRegClassID > + && OpInfo[2].RegClass == ARM::GPRRegClassID > + && OpInfo[3].RegClass == 0); > + > + // Add the operands. > + MI.addOperand(MCOperand::CreateReg(getRegisterEnum(ARM::GPRRegClassID, > + decodeRd(insn)))); > + MI.addOperand(MCOperand::CreateReg(getRegisterEnum(ARM::GPRRegClassID, > + decodeRs(insn)))); > + MI.addOperand(MCOperand::CreateReg(getRegisterEnum(ARM::GPRRegClassID, > + decodeRn(insn)))); > + > + // Finally add (+/-)imm8*4, depending on the U bit. > + int Offset = getImm8(insn) * 4; > + if (getUBit(insn) == 0) > + Offset = -Offset; > + MI.addOperand(MCOperand::CreateImm(Offset)); > + NumOpsAdded = 4; > + > + return true; > +} > + > +// PC-based defined for Codegen, which do not get decoded by design: > +// > +// t2TBB, t2TBH: Rm immDontCare immDontCare > +// > +// Generic version defined for disassembly: > +// > +// t2TBBgen, t2TBHgen: Rn Rm Pred-Imm Pred-CCR > +static bool DisassembleThumb2TB(MCInst &MI, unsigned Opcode, > + uint32_t insn, unsigned short NumOps, unsigned &NumOpsAdded) { > + > + assert(NumOps >= 2); > + > + // The generic version of TBB/TBH needs a base register. > + MI.addOperand(MCOperand::CreateReg(getRegisterEnum(ARM::GPRRegClassID, > + decodeRn(insn)))); > + // Add the index register. > + MI.addOperand(MCOperand::CreateReg(getRegisterEnum(ARM::GPRRegClassID, > + decodeRm(insn)))); > + NumOpsAdded = 2; > + > + return true; > +} > + > +static inline bool Thumb2ShiftOpcode(unsigned Opcode) { > + switch (Opcode) { > + default: > + return false; > + case ARM::t2MOVCClsl: case ARM::t2MOVCClsr: > + case ARM::t2MOVCCasr: case ARM::t2MOVCCror: > + case ARM::t2LSLri: case ARM::t2LSRri: > + case ARM::t2ASRri: case ARM::t2RORri: > + return true; > + } > +} > + > +// A6.3.11 Data-processing (shifted register) > +// > +// Two register operands (Rn=0b1111 no 1st operand reg): Rs Rm > +// Two register operands (Rs=0b1111 no dst operand reg): Rn Rm > +// Three register operands: Rs Rn Rm > +// Three register operands: (Rn=0b1111 Conditional Move) Rs Ro(TIED_TO) Rm > +// > +// Constant shifts t2_so_reg is a 2-operand unit corresponding to the Thumb2 > +// register with shift forms: (Rm, ConstantShiftSpecifier). > +// Constant shift specifier: Imm = (ShOp | ShAmt<<3). > +// > +// There are special instructions, like t2MOVsra_flag and t2MOVsrl_flag, which > +// only require two register operands: Rd, Rm in ARM Reference Manual terms, and > +// nothing else, because the shift amount is already specified. > +// Similar case holds for t2MOVrx, t2ADDrr, ..., etc. > +static bool DisassembleThumb2DPSoReg(MCInst &MI, unsigned Opcode, uint32_t insn, > + unsigned short NumOps, unsigned &NumOpsAdded) { > + > + const TargetInstrDesc &TID = ARMInsts[Opcode]; > + const TargetOperandInfo *OpInfo = TID.OpInfo; > + unsigned &OpIdx = NumOpsAdded; > + > + // Special case handling. > + if (Opcode == ARM::t2BR_JT) { > + assert(NumOps == 4 > + && OpInfo[0].RegClass == ARM::GPRRegClassID > + && OpInfo[1].RegClass == ARM::GPRRegClassID > + && OpInfo[2].RegClass == 0 > + && OpInfo[3].RegClass == 0); > + // Only need to populate the src reg operand. > + MI.addOperand(MCOperand::CreateReg(getRegisterEnum(ARM::GPRRegClassID, > + decodeRm(insn)))); > + MI.addOperand(MCOperand::CreateReg(0)); > + MI.addOperand(MCOperand::CreateImm(0)); > + MI.addOperand(MCOperand::CreateImm(0)); > + NumOpsAdded = 4; > + return true; > + } > + > + OpIdx = 0; > + > + assert(NumOps >= 2 > + && OpInfo[0].RegClass == ARM::GPRRegClassID > + && OpInfo[1].RegClass == ARM::GPRRegClassID); > + > + bool ThreeReg = (NumOps > 2 && OpInfo[2].RegClass == ARM::GPRRegClassID); > + bool NoDstReg = (decodeRs(insn) == 0xF); > + > + // Build the register operands, followed by the constant shift specifier. > + > + MI.addOperand(MCOperand::CreateReg( > + getRegisterEnum(ARM::GPRRegClassID, > + NoDstReg ? decodeRn(insn) : decodeRs(insn)))); > + ++OpIdx; > + > + if (ThreeReg) { > + int Idx; > + if ((Idx = TID.getOperandConstraint(OpIdx, TOI::TIED_TO)) != -1) { > + // Process tied_to operand constraint. > + MI.addOperand(MI.getOperand(Idx)); > + } else { > + assert(!NoDstReg); > + MI.addOperand(MCOperand::CreateReg(getRegisterEnum(ARM::GPRRegClassID, > + decodeRn(insn)))); > + } > + ++OpIdx; > + } > + > + MI.addOperand(MCOperand::CreateReg(getRegisterEnum(ARM::GPRRegClassID, > + decodeRm(insn)))); > + ++OpIdx; > + > + if (NumOps == OpIdx) > + return true; > + > + if (OpInfo[OpIdx].RegClass == 0 && !OpInfo[OpIdx].isPredicate() > + && !OpInfo[OpIdx].isOptionalDef()) { > + > + if (Thumb2ShiftOpcode(Opcode)) > + MI.addOperand(MCOperand::CreateImm(getShiftAmtBits(insn))); > + else { > + // Build the constant shift specifier operand. > + unsigned bits2 = getShiftTypeBits(insn); > + unsigned imm5 = getShiftAmtBits(insn); > + ARM_AM::ShiftOpc ShOp = ARM_AM::no_shift; > + unsigned ShAmt = decodeImmShift(bits2, imm5, ShOp); > + > + // PKHBT/PKHTB are special in that we need the decodeImmShift() call to > + // decode the shift amount from raw imm5 and bits2, but we DO NOT need > + // to encode the ShOp, as it's in the asm string already. > + if (Opcode == ARM::t2PKHBT || Opcode == ARM::t2PKHTB) > + MI.addOperand(MCOperand::CreateImm(ShAmt)); > + else > + MI.addOperand(MCOperand::CreateImm(ARM_AM::getSORegOpc(ShOp, ShAmt))); > + } > + ++OpIdx; > + } > + > + return true; > +} > + > +// A6.3.1 Data-processing (modified immediate) > +// > +// Two register operands: Rs Rn ModImm > +// One register operands (Rs=0b1111 no explicit dest reg): Rn ModImm > +// One register operands (Rn=0b1111 no explicit src reg): Rs ModImm - {t2MOVi, t2MVNi} > +// > +// ModImm = ThumbExpandImm(i:imm3:imm8) > +static bool DisassembleThumb2DPModImm(MCInst &MI, unsigned Opcode, > + uint32_t insn, unsigned short NumOps, unsigned &NumOpsAdded) { > + > + const TargetOperandInfo *OpInfo = ARMInsts[Opcode].OpInfo; > + unsigned &OpIdx = NumOpsAdded; > + > + OpIdx = 0; > + > + assert(NumOps >= 2 && OpInfo[0].RegClass == ARM::GPRRegClassID); > + > + bool TwoReg = (OpInfo[1].RegClass == ARM::GPRRegClassID); > + bool NoDstReg = (decodeRs(insn) == 0xF); > + > + // Build the register operands, followed by the modified immediate. > + > + MI.addOperand(MCOperand::CreateReg( > + getRegisterEnum(ARM::GPRRegClassID, > + NoDstReg ? decodeRn(insn) : decodeRs(insn)))); > + ++OpIdx; > + > + if (TwoReg) { > + assert(!NoDstReg); > + MI.addOperand(MCOperand::CreateReg(getRegisterEnum(ARM::GPRRegClassID, > + decodeRn(insn)))); > + ++OpIdx; > + } > + > + // The modified immediate operand should come next. > + assert(OpIdx < NumOps && OpInfo[OpIdx].RegClass == 0 && > + !OpInfo[OpIdx].isPredicate() && !OpInfo[OpIdx].isOptionalDef()); > + > + // i:imm3:imm8 > + // A6.3.2 Modified immediate constants in Thumb instructions > + unsigned imm12 = getIImm3Imm8(insn); > + MI.addOperand(MCOperand::CreateImm(ThumbExpandImm(imm12))); > + ++OpIdx; > + > + return true; > +} > + > +static inline bool Thumb2SaturateOpcode(unsigned Opcode) { > + switch (Opcode) { > + case ARM::t2SSATlsl: case ARM::t2SSATasr: case ARM::t2SSAT16: > + case ARM::t2USATlsl: case ARM::t2USATasr: case ARM::t2USAT16: > + return true; > + default: > + return false; > + } > +} > + > +static inline unsigned decodeThumb2SaturatePos(unsigned Opcode, uint32_t insn) { > + switch (Opcode) { > + case ARM::t2SSATlsl: > + case ARM::t2SSATasr: > + return slice(insn, 4, 0) + 1; > + case ARM::t2SSAT16: > + return slice(insn, 3, 0) + 1; > + case ARM::t2USATlsl: > + case ARM::t2USATasr: > + return slice(insn, 4, 0); > + case ARM::t2USAT16: > + return slice(insn, 3, 0); > + default: > + llvm_unreachable("Invalid opcode passed in"); > + return 0; > + } > +} > + > +// A6.3.3 Data-processing (plain binary immediate) > +// > +// o t2ADDri12, t2SUBri12: Rs Rn imm12 > +// o t2LEApcrel (ADR): Rs imm12 > +// o t2BFC (BFC): Rs Ro(TIED_TO) bf_inv_mask_imm > +// o t2BFI (BFI) (Currently not defined in LLVM as of Jan-07-2010) > +// o t2MOVi16: Rs imm16 > +// o t2MOVTi16: Rs imm16 > +// o t2SBFX (SBFX): Rs Rn lsb width > +// o t2UBFX (UBFX): Rs Rn lsb width > +// o t2BFI (BFI): Rs Rn lsb width > +// > +// [Signed|Unsigned] Saturate [16] > +// > +// o t2SSAT[lsl|asr], t2USAT[lsl|asr]: Rs sat_pos Rn shamt > +// o t2SSAT16, t2USAT16: Rs sat_pos Rn > +static bool DisassembleThumb2DPBinImm(MCInst &MI, unsigned Opcode, > + uint32_t insn, unsigned short NumOps, unsigned &NumOpsAdded) { > + > + const TargetInstrDesc &TID = ARMInsts[Opcode]; > + const TargetOperandInfo *OpInfo = TID.OpInfo; > + unsigned &OpIdx = NumOpsAdded; > + > + OpIdx = 0; > + > + assert(NumOps >= 2 && OpInfo[0].RegClass == ARM::GPRRegClassID); > + > + bool TwoReg = (OpInfo[1].RegClass == ARM::GPRRegClassID); > + > + // Build the register operand(s), followed by the immediate(s). > + > + MI.addOperand(MCOperand::CreateReg(getRegisterEnum(ARM::GPRRegClassID, > + decodeRs(insn)))); > + ++OpIdx; > + > + // t2SSAT/t2SSAT16/t2USAT/t2USAT16 has imm operand after Rd. > + if (Thumb2SaturateOpcode(Opcode)) { > + MI.addOperand(MCOperand::CreateImm(decodeThumb2SaturatePos(Opcode, insn))); > + > + MI.addOperand(MCOperand::CreateReg(getRegisterEnum(ARM::GPRRegClassID, > + decodeRn(insn)))); > + > + if (Opcode == ARM::t2SSAT16 || Opcode == ARM::t2USAT16) { > + OpIdx += 2; > + return true; > + } > + > + // For SSAT operand reg (Rn) has been disassembled above. > + // Now disassemble the shift amount. > + > + // Inst{14-12:7-6} encodes the imm5 shift amount. > + unsigned ShAmt = slice(insn, 14, 12) << 2 | slice(insn, 7, 6); > + > + MI.addOperand(MCOperand::CreateImm(ShAmt)); > + > + OpIdx += 3; > + return true; > + } > + > + if (TwoReg) { > + assert(NumOps >= 3); > + int Idx; > + if ((Idx = TID.getOperandConstraint(OpIdx, TOI::TIED_TO)) != -1) { > + // Process tied_to operand constraint. > + MI.addOperand(MI.getOperand(Idx)); > + } else { > + // Add src reg operand. > + MI.addOperand(MCOperand::CreateReg(getRegisterEnum(ARM::GPRRegClassID, > + decodeRn(insn)))); > + } > + ++OpIdx; > + } > + > + assert(OpInfo[OpIdx].RegClass == 0 && !OpInfo[OpIdx].isPredicate() > + && !OpInfo[OpIdx].isOptionalDef()); > + > + // Pre-increment OpIdx. > + ++OpIdx; > + > + if (Opcode == ARM::t2ADDri12 || Opcode == ARM::t2SUBri12 > + || Opcode == ARM::t2LEApcrel) > + MI.addOperand(MCOperand::CreateImm(getIImm3Imm8(insn))); > + else if (Opcode == ARM::t2MOVi16 || Opcode == ARM::t2MOVTi16) > + MI.addOperand(MCOperand::CreateImm(getImm16(insn))); > + else if (Opcode == ARM::t2BFC) > + MI.addOperand(MCOperand::CreateImm(getBitfieldInvMask(insn))); > + else { > + // Handle the case of: lsb width > + assert(Opcode == ARM::t2SBFX || Opcode == ARM::t2UBFX || > + Opcode == ARM::t2BFI); > + MI.addOperand(MCOperand::CreateImm(getLsb(insn))); > + if (Opcode == ARM::t2BFI) { > + assert(getMsb(insn) >= getLsb(insn)); > + MI.addOperand(MCOperand::CreateImm(getMsb(insn) - getLsb(insn) + 1)); > + } else > + MI.addOperand(MCOperand::CreateImm(getWidthMinus1(insn) + 1)); > + > + ++OpIdx; > + } > + > + return true; > +} > + > +// A6.3.4 Table A6-15 Miscellaneous control instructions > +// A8.6.41 DMB > +// A8.6.42 DSB > +// A8.6.49 ISB > +static inline bool t2MiscCtrlInstr(uint32_t insn) { > + if (slice(insn, 31, 20) == 0xf3b && slice(insn, 15, 14) == 2 && > + slice(insn, 12, 12) == 0) > + return true; > + > + return false; > +} > + > +// A6.3.4 Branches and miscellaneous control > +// > +// A8.6.16 B > +// Branches: t2B, t2Bcc -> imm operand > +// > +// Branches: t2TPsoft -> no operand > +// > +// A8.6.23 BL, BLX (immediate) > +// Branches (defined in ARMInstrThumb.td): tBLr9, tBLXi_r9 -> imm operand > +// > +// A8.6.26 > +// t2BXJ -> Rn > +// > +// Miscellaneous control: t2Int_MemBarrierV7 (and its t2DMB variants), > +// t2Int_SyncBarrierV7 (and its t2DSB varianst), t2ISBsy, t2CLREX > +// -> no operand (except pred-imm pred-ccr for CLREX, memory barrier variants) > +// > +// Hint: t2NOP, t2YIELD, t2WFE, t2WFI, t2SEV > +// -> no operand (except pred-imm pred-ccr) > +// > +// t2DBG -> imm4 = Inst{3-0} > +// > +// t2MRS/t2MRSsys -> Rs > +// t2MSR/t2MSRsys -> Rn mask=Inst{11-8} > +// t2SMC -> imm4 = Inst{19-16} > +static bool DisassembleThumb2BrMiscCtrl(MCInst &MI, unsigned Opcode, > + uint32_t insn, unsigned short NumOps, unsigned &NumOpsAdded) { > + > + if (NumOps == 0) > + return true; > + > + if (t2MiscCtrlInstr(insn)) > + return true; > + > + switch (Opcode) { > + case ARM::t2CLREX: > + case ARM::t2NOP: > + case ARM::t2YIELD: > + case ARM::t2WFE: > + case ARM::t2WFI: > + case ARM::t2SEV: > + return true; > + default: > + break; > + } > + > + // CPS has a singleton $opt operand that contains the following information: > + // opt{4-0} = mode from Inst{4-0} > + // opt{5} = changemode from Inst{8} > + // opt{8-6} = AIF from Inst{7-5} > + // opt{10-9} = imod from Inst{10-9} with 0b10 as enable and 0b11 as disable > + if (Opcode == ARM::t2CPS) { > + unsigned Option = slice(insn, 4, 0) | slice(insn, 8, 8) << 5 | > + slice(insn, 7, 5) << 6 | slice(insn, 10, 9) << 9; > + MI.addOperand(MCOperand::CreateImm(Option)); > + NumOpsAdded = 1; > + return true; > + } > + > + // DBG has its option specified in Inst{3-0}. > + if (Opcode == ARM::t2DBG) { > + MI.addOperand(MCOperand::CreateImm(slice(insn, 3, 0))); > + NumOpsAdded = 1; > + return true; > + } > + > + // MRS and MRSsys take one GPR reg Rs. > + if (Opcode == ARM::t2MRS || Opcode == ARM::t2MRSsys) { > + MI.addOperand(MCOperand::CreateReg(getRegisterEnum(ARM::GPRRegClassID, > + decodeRs(insn)))); > + NumOpsAdded = 1; > + return true; > + } > + // BXJ takes one GPR reg Rn. > + if (Opcode == ARM::t2BXJ) { > + MI.addOperand(MCOperand::CreateReg(getRegisterEnum(ARM::GPRRegClassID, > + decodeRn(insn)))); > + NumOpsAdded = 1; > + return true; > + } > + // MSR and MSRsys take one GPR reg Rn, followed by the mask. > + if (Opcode == ARM::t2MSR || Opcode == ARM::t2MSRsys || Opcode == ARM::t2BXJ) { > + MI.addOperand(MCOperand::CreateReg(getRegisterEnum(ARM::GPRRegClassID, > + decodeRn(insn)))); > + MI.addOperand(MCOperand::CreateImm(slice(insn, 11, 8))); > + NumOpsAdded = 2; > + return true; > + } > + // SMC take imm4. > + if (Opcode == ARM::t2SMC) { > + MI.addOperand(MCOperand::CreateImm(slice(insn, 19, 16))); > + NumOpsAdded = 1; > + return true; > + } > + > + // Add the imm operand. > + int Offset = 0; > + > + switch (Opcode) { > + default: > + assert(0 && "Unreachable code"); > + case ARM::t2B: > + Offset = decodeImm32_B_EncodingT4(insn); > + break; > + case ARM::t2Bcc: > + Offset = decodeImm32_B_EncodingT3(insn); > + break; > + case ARM::tBLr9: > + Offset = decodeImm32_BL(insn); > + break; > + case ARM::tBLXi_r9: > + Offset = decodeImm32_BLX(insn); > + break; > + } > + // When executing a Thumb instruction, PC reads as the address of the current > + // instruction plus 4. The assembler subtracts 4 from the difference between > + // the branch instruction and the target address, disassembler has to add 4 to > + // to compensate. > + MI.addOperand(MCOperand::CreateImm(Offset + 4)); > + > + NumOpsAdded = 1; > + > + return true; > +} > + > +static inline bool Thumb2PreloadOpcode(unsigned Opcode) { > + switch (Opcode) { > + default: > + return false; > + case ARM::t2PLDi12: case ARM::t2PLDi8: case ARM::t2PLDpci: > + case ARM::t2PLDr: case ARM::t2PLDs: > + case ARM::t2PLDWi12: case ARM::t2PLDWi8: case ARM::t2PLDWpci: > + case ARM::t2PLDWr: case ARM::t2PLDWs: > + case ARM::t2PLIi12: case ARM::t2PLIi8: case ARM::t2PLIpci: > + case ARM::t2PLIr: case ARM::t2PLIs: > + return true; > + } > +} > + > +static bool DisassembleThumb2PreLoad(MCInst &MI, unsigned Opcode, uint32_t insn, > + unsigned short NumOps, unsigned &NumOpsAdded) { > + > + // Preload Data/Instruction requires either 2 or 3 operands. > + // t2PLDi12, t2PLDi8, t2PLDpci: Rn [+/-]imm12/imm8 > + // t2PLDr: Rn Rm > + // t2PLDs: Rn Rm imm2=Inst{5-4} > + // Same pattern applies for t2PLDW* and t2PLI*. > + > + const TargetInstrDesc &TID = ARMInsts[Opcode]; > + const TargetOperandInfo *OpInfo = TID.OpInfo; > + unsigned &OpIdx = NumOpsAdded; > + > + OpIdx = 0; > + > + assert(NumOps >= 2 && > + OpInfo[0].RegClass == ARM::GPRRegClassID); > + > + MI.addOperand(MCOperand::CreateReg(getRegisterEnum(ARM::GPRRegClassID, > + decodeRn(insn)))); > + ++OpIdx; > + > + if (OpInfo[OpIdx].RegClass == ARM::GPRRegClassID) { > + MI.addOperand(MCOperand::CreateReg(getRegisterEnum(ARM::GPRRegClassID, > + decodeRm(insn)))); > + } else { > + assert(OpInfo[OpIdx].RegClass == 0 && !OpInfo[OpIdx].isPredicate() > + && !OpInfo[OpIdx].isOptionalDef()); > + int Offset = 0; > + if (Opcode == ARM::t2PLDpci || Opcode == ARM::t2PLDWpci || > + Opcode == ARM::t2PLIpci) { > + bool Negative = slice(insn, 23, 23) == 0; > + unsigned Imm12 = getImm12(insn); > + Offset = Negative ? -1 - Imm12 : 1 * Imm12; > + } else if (Opcode == ARM::t2PLDi8 || Opcode == ARM::t2PLDWi8 || > + Opcode == ARM::t2PLIi8) { > + // A8.6.117 Encoding T2: add = FALSE > + unsigned Imm8 = getImm8(insn); > + Offset = -1 - Imm8; > + } else // The i12 forms. See, for example, A8.6.117 Encoding T1. > + Offset = decodeImm12(insn); > + MI.addOperand(MCOperand::CreateImm(Offset)); > + } > + ++OpIdx; > + > + if (OpIdx < NumOps && OpInfo[OpIdx].RegClass == 0 && > + !OpInfo[OpIdx].isPredicate() && !OpInfo[OpIdx].isOptionalDef()) { > + // Fills in the shift amount for t2PLDs, t2PLDWs, t2PLIs. > + MI.addOperand(MCOperand::CreateImm(slice(insn, 5, 4))); > + ++OpIdx; > + } > + > + return true; > +} > + > +// A8.6.63 LDRB (literal) > +// A8.6.79 LDRSB (literal) > +// A8.6.75 LDRH (literal) > +// A8.6.83 LDRSH (literal) > +// A8.6.59 LDR (literal) > +// > +// These instrs calculate an address from the PC value and an immediate offset. > +// Rd Rn=PC (+/-)imm12 (+ if Inst{23} == 0b1) > +static bool DisassembleThumb2Ldpci(MCInst &MI, unsigned Opcode, > + uint32_t insn, unsigned short NumOps, unsigned &NumOpsAdded) { > + > + const TargetOperandInfo *OpInfo = ARMInsts[Opcode].OpInfo; > + > + assert(NumOps >= 2 && > + OpInfo[0].RegClass == ARM::GPRRegClassID && > + OpInfo[1].RegClass == 0); > + > + // Build the register operand, followed by the (+/-)imm12 immediate. > + > + MI.addOperand(MCOperand::CreateReg(getRegisterEnum(ARM::GPRRegClassID, > + decodeRd(insn)))); > + > + MI.addOperand(MCOperand::CreateImm(decodeImm12(insn))); > + > + NumOpsAdded = 2; > + > + return true; > +} > + > +// A6.3.10 Store single data item > +// A6.3.9 Load byte, memory hints > +// A6.3.8 Load halfword, memory hints > +// A6.3.7 Load word > +// > +// For example, > +// > +// t2LDRi12: Rd Rn (+)imm12 > +// t2LDRi8: Rd Rn (+/-)imm8 (+ if Inst{9} == 0b1) > +// t2LDRs: Rd Rn Rm ConstantShiftSpecifier (see also DisassembleThumb2DPSoReg) > +// t2LDR_POST: Rd Rn Rn(TIED_TO) (+/-)imm8 (+ if Inst{9} == 0b1) > +// t2LDR_PRE: Rd Rn Rn(TIED_TO) (+/-)imm8 (+ if Inst{9} == 0b1) > +// > +// t2STRi12: Rd Rn (+)imm12 > +// t2STRi8: Rd Rn (+/-)imm8 (+ if Inst{9} == 0b1) > +// t2STRs: Rd Rn Rm ConstantShiftSpecifier (see also DisassembleThumb2DPSoReg) > +// t2STR_POST: Rn Rd Rn(TIED_TO) (+/-)imm8 (+ if Inst{9} == 0b1) > +// t2STR_PRE: Rn Rd Rn(TIED_TO) (+/-)imm8 (+ if Inst{9} == 0b1) > +// > +// Note that for indexed modes, the Rn(TIED_TO) operand needs to be populated > +// correctly, as LLVM AsmPrinter depends on it. For indexed stores, the first > +// operand is Rn; for all the other instructions, Rd is the first operand. > +// > +// Delegates to DisassembleThumb2PreLoad() for preload data/instruction. > +// Delegates to DisassembleThumb2Ldpci() for load * literal operations. > +static bool DisassembleThumb2LdSt(bool Load, MCInst &MI, unsigned Opcode, > + uint32_t insn, unsigned short NumOps, unsigned &NumOpsAdded) { > + > + unsigned Rn = decodeRn(insn); > + > + if (Thumb2PreloadOpcode(Opcode)) > + return DisassembleThumb2PreLoad(MI, Opcode, insn, NumOps, NumOpsAdded); > + > + // See, for example, A6.3.7 Load word: Table A6-18 Load word. > + if (Load && Rn == 15) > + return DisassembleThumb2Ldpci(MI, Opcode, insn, NumOps, NumOpsAdded); > + > + const TargetInstrDesc &TID = ARMInsts[Opcode]; > + const TargetOperandInfo *OpInfo = TID.OpInfo; > + unsigned &OpIdx = NumOpsAdded; > + > + OpIdx = 0; > + > + assert(NumOps >= 3 && > + OpInfo[0].RegClass == ARM::GPRRegClassID && > + OpInfo[1].RegClass == ARM::GPRRegClassID); > + > + bool ThreeReg = (OpInfo[2].RegClass == ARM::GPRRegClassID); > + bool TIED_TO = ThreeReg && TID.getOperandConstraint(2, TOI::TIED_TO) != -1; > + bool Imm12 = !ThreeReg && slice(insn, 23, 23) == 1; // ARMInstrThumb2.td > + > + // Build the register operands, followed by the immediate. > + unsigned R0, R1, R2 = 0; > + unsigned Rd = decodeRd(insn); > + int Imm = 0; > + > + if (!Load && TIED_TO) { > + R0 = Rn; > + R1 = Rd; > + } else { > + R0 = Rd; > + R1 = Rn; > + } > + if (ThreeReg) { > + if (TIED_TO) { > + R2 = Rn; > + Imm = decodeImm8(insn); > + } else { > + R2 = decodeRm(insn); > + // See, for example, A8.6.64 LDRB (register). > + // And ARMAsmPrinter::printT2AddrModeSoRegOperand(). > + // LSL is the default shift opc, and LLVM does not expect it to be encoded > + // as part of the immediate operand. > + // Imm = ARM_AM::getSORegOpc(ARM_AM::lsl, slice(insn, 5, 4)); > + Imm = slice(insn, 5, 4); > + } > + } else { > + if (Imm12) > + Imm = getImm12(insn); > + else > + Imm = decodeImm8(insn); > + } > + > + MI.addOperand(MCOperand::CreateReg(getRegisterEnum(ARM::GPRRegClassID, R0))); > + ++OpIdx; > + MI.addOperand(MCOperand::CreateReg(getRegisterEnum(ARM::GPRRegClassID, R1))); > + ++OpIdx; > + > + if (ThreeReg) { > + MI.addOperand(MCOperand::CreateReg(getRegisterEnum(ARM::GPRRegClassID,R2))); > + ++OpIdx; > + } > + > + assert(OpInfo[OpIdx].RegClass == 0 && !OpInfo[OpIdx].isPredicate() > + && !OpInfo[OpIdx].isOptionalDef()); > + > + MI.addOperand(MCOperand::CreateImm(Imm)); > + ++OpIdx; > + > + return true; > +} > + > +// A6.3.12 Data-processing (register) > +// > +// Two register operands [rotate]: Rs Rm [rotation(= (rotate:'000'))] > +// Three register operands only: Rs Rn Rm > +// Three register operands [rotate]: Rs Rn Rm [rotation(= (rotate:'000'))] > +// > +// Parallel addition and subtraction 32-bit Thumb instructions: Rs Rn Rm > +// > +// Miscellaneous operations: Rs [Rn] Rm > +static bool DisassembleThumb2DPReg(MCInst &MI, unsigned Opcode, uint32_t insn, > + unsigned short NumOps, unsigned &NumOpsAdded) { > + > + const TargetInstrDesc &TID = ARMInsts[Opcode]; > + const TargetOperandInfo *OpInfo = TID.OpInfo; > + unsigned &OpIdx = NumOpsAdded; > + > + OpIdx = 0; > + > + assert(NumOps >= 2 && > + OpInfo[0].RegClass == ARM::GPRRegClassID && > + OpInfo[1].RegClass == ARM::GPRRegClassID); > + > + // Build the register operands, followed by the optional rotation amount. > + > + bool ThreeReg = NumOps > 2 && OpInfo[2].RegClass == ARM::GPRRegClassID; > + > + MI.addOperand(MCOperand::CreateReg(getRegisterEnum(ARM::GPRRegClassID, > + decodeRs(insn)))); > + ++OpIdx; > + > + if (ThreeReg) { > + MI.addOperand(MCOperand::CreateReg(getRegisterEnum(ARM::GPRRegClassID, > + decodeRn(insn)))); > + ++OpIdx; > + } > + > + MI.addOperand(MCOperand::CreateReg(getRegisterEnum(ARM::GPRRegClassID, > + decodeRm(insn)))); > + ++OpIdx; > + > + if (OpIdx < NumOps && OpInfo[OpIdx].RegClass == 0 > + && !OpInfo[OpIdx].isPredicate() && !OpInfo[OpIdx].isOptionalDef()) { > + // Add the rotation amount immediate. > + MI.addOperand(MCOperand::CreateImm(decodeRotate(insn))); > + ++OpIdx; > + } > + > + return true; > +} > + > +// A6.3.16 Multiply, multiply accumulate, and absolute difference > +// > +// t2MLA, t2MLS, t2SMMLA, t2SMMLS: Rs Rn Rm Ra=Inst{15-12} > +// t2MUL, t2SMMUL: Rs Rn Rm > +// t2SMLA[BB|BT|TB|TT|WB|WT]: Rs Rn Rm Ra=Inst{15-12} > +// t2SMUL[BB|BT|TB|TT|WB|WT]: Rs Rn Rm > +// > +// Dual halfword multiply: t2SMUAD[X], t2SMUSD[X], t2SMLAD[X], t2SMLSD[X]: > +// Rs Rn Rm Ra=Inst{15-12} > +// > +// Unsigned Sum of Absolute Differences [and Accumulate] > +// Rs Rn Rm [Ra=Inst{15-12}] > +static bool DisassembleThumb2Mul(MCInst &MI, unsigned Opcode, uint32_t insn, > + unsigned short NumOps, unsigned &NumOpsAdded) { > + > + const TargetOperandInfo *OpInfo = ARMInsts[Opcode].OpInfo; > + > + assert(NumOps >= 3 && > + OpInfo[0].RegClass == ARM::GPRRegClassID && > + OpInfo[1].RegClass == ARM::GPRRegClassID && > + OpInfo[2].RegClass == ARM::GPRRegClassID); > + > + // Build the register operands. > + > + bool FourReg = NumOps > 3 && OpInfo[3].RegClass == ARM::GPRRegClassID; > + > + MI.addOperand(MCOperand::CreateReg(getRegisterEnum(ARM::GPRRegClassID, > + decodeRs(insn)))); > + > + MI.addOperand(MCOperand::CreateReg(getRegisterEnum(ARM::GPRRegClassID, > + decodeRn(insn)))); > + > + MI.addOperand(MCOperand::CreateReg(getRegisterEnum(ARM::GPRRegClassID, > + decodeRm(insn)))); > + > + if (FourReg) > + MI.addOperand(MCOperand::CreateReg(getRegisterEnum(ARM::GPRRegClassID, > + decodeRd(insn)))); > + > + NumOpsAdded = FourReg ? 4 : 3; > + > + return true; > +} > + > +// A6.3.17 Long multiply, long multiply accumulate, and divide > +// > +// t2SMULL, t2UMULL, t2SMLAL, t2UMLAL, t2UMAAL: RdLo RdHi Rn Rm > +// where RdLo = Inst{15-12} and RdHi = Inst{11-8} > +// > +// Halfword multiple accumulate long: t2SMLAL: RdLo RdHi Rn Rm > +// where RdLo = Inst{15-12} and RdHi = Inst{11-8} > +// > +// Dual halfword multiple: t2SMLALD[X], t2SMLSLD[X]: RdLo RdHi Rn Rm > +// where RdLo = Inst{15-12} and RdHi = Inst{11-8} > +// > +// Signed/Unsigned divide: t2SDIV, t2UDIV: Rs Rn Rm > +static bool DisassembleThumb2LongMul(MCInst &MI, unsigned Opcode, uint32_t insn, > + unsigned short NumOps, unsigned &NumOpsAdded) { > + > + const TargetOperandInfo *OpInfo = ARMInsts[Opcode].OpInfo; > + > + assert(NumOps >= 3 && > + OpInfo[0].RegClass == ARM::GPRRegClassID && > + OpInfo[1].RegClass == ARM::GPRRegClassID && > + OpInfo[2].RegClass == ARM::GPRRegClassID); > + > + bool FourReg = NumOps > 3 && OpInfo[3].RegClass == ARM::GPRRegClassID; > + > + // Build the register operands. > + > + if (FourReg) > + MI.addOperand(MCOperand::CreateReg(getRegisterEnum(ARM::GPRRegClassID, > + decodeRd(insn)))); > + > + MI.addOperand(MCOperand::CreateReg(getRegisterEnum(ARM::GPRRegClassID, > + decodeRs(insn)))); > + > + MI.addOperand(MCOperand::CreateReg(getRegisterEnum(ARM::GPRRegClassID, > + decodeRn(insn)))); > + > + MI.addOperand(MCOperand::CreateReg(getRegisterEnum(ARM::GPRRegClassID, > + decodeRm(insn)))); > + > + if (FourReg) > + NumOpsAdded = 4; > + else > + NumOpsAdded = 3; > + > + return true; > +} > + > +// See A6.3 32-bit Thumb instruction encoding for instruction classes > +// corresponding to (op1, op2, op). > +// > +// Table A6-9 32-bit Thumb instruction encoding > +// op1 op2 op Instruction class, see > +// --- ------- -- ------------------------------------------------------------ > +// 01 00xx0xx - Load/store multiple on page A6-23 > +// 00xx1xx - Load/store dual, load/store exclusive, table branch on page A6-24 > +// 01xxxxx - Data-processing (shifted register) on page A6-31 > +// 1xxxxxx - Coprocessor instructions on page A6-40 > +// 10 x0xxxxx 0 Data-processing (modified immediate) on page A6-15 > +// x1xxxxx 0 Data-processing (plain binary immediate) on page A6-19 > +// - 1 Branches and miscellaneous control on page A6-20 > +// 11 000xxx0 - Store single data item on page A6-30 > +// 001xxx0 - Advanced SIMD element or structure load/store instructions on page A7-27 > +// 00xx001 - Load byte, memory hints on page A6-28 > +// 00xx011 - Load halfword, memory hints on page A6-26 > +// 00xx101 - Load word on page A6-25 > +// 00xx111 - UNDEFINED > +// 010xxxx - Data-processing (register) on page A6-33 > +// 0110xxx - Multiply, multiply accumulate, and absolute difference on page A6-38 > +// 0111xxx - Long multiply, long multiply accumulate, and divide on page A6-39 > +// 1xxxxxx - Coprocessor instructions on page A6-40 > +// > +static bool DisassembleThumb2(uint16_t op1, uint16_t op2, uint16_t op, > + MCInst &MI, unsigned Opcode, uint32_t insn, > + unsigned short NumOps, unsigned &NumOpsAdded) { > + > + switch (op1) { > + case 1: > + if (slice(op2, 6, 5) == 0) { > + if (slice(op2, 2, 2) == 0) { > + // Load/store multiple. > + return DisassembleThumb2LdStMul(MI, Opcode, insn, NumOps, NumOpsAdded); > + } > + > + // Load/store dual, load/store exclusive, table branch, otherwise. > + assert(slice(op2, 2, 2) == 1); > + if ((ARM::t2LDREX <= Opcode && Opcode <= ARM::t2LDREXH) || > + (ARM::t2STREX <= Opcode && Opcode <= ARM::t2STREXH)) { > + // Load/store exclusive. > + return DisassembleThumb2LdStEx(MI, Opcode, insn, NumOps, NumOpsAdded); > + } > + if (Opcode == ARM::t2LDRDi8 || > + Opcode == ARM::t2LDRD_PRE || Opcode == ARM::t2LDRD_POST || > + Opcode == ARM::t2STRDi8 || > + Opcode == ARM::t2STRD_PRE || Opcode == ARM::t2STRD_POST) { > + // Load/store dual. > + return DisassembleThumb2LdStDual(MI, Opcode, insn, NumOps, NumOpsAdded); > + } > + if (Opcode == ARM::t2TBBgen || Opcode == ARM::t2TBHgen) { > + // Table branch. > + return DisassembleThumb2TB(MI, Opcode, insn, NumOps, NumOpsAdded); > + } > + } else if (slice(op2, 6, 5) == 1) { > + // Data-processing (shifted register). > + return DisassembleThumb2DPSoReg(MI, Opcode, insn, NumOps, NumOpsAdded); > + } > + > + // FIXME: A6.3.18 Coprocessor instructions > + // But see ThumbDisassembler::getInstruction(). > + > + break; > + case 2: > + if (op == 0) { > + if (slice(op2, 5, 5) == 0) { > + // Data-processing (modified immediate) > + return DisassembleThumb2DPModImm(MI, Opcode, insn, NumOps, NumOpsAdded); > + } else { > + // Data-processing (plain binary immediate) > + return DisassembleThumb2DPBinImm(MI, Opcode, insn, NumOps, NumOpsAdded); > + } > + } else { > + // Branches and miscellaneous control on page A6-20. > + return DisassembleThumb2BrMiscCtrl(MI, Opcode, insn, NumOps, NumOpsAdded); > + } > + > + break; > + case 3: > + switch (slice(op2, 6, 5)) { > + case 0: > + // Load/store instructions... > + if (slice(op2, 0, 0) == 0) { > + if (slice(op2, 4, 4) == 0) { > + // Store single data item on page A6-30 > + return DisassembleThumb2LdSt(false, MI,Opcode,insn,NumOps,NumOpsAdded); > + } else { > + // FIXME: Advanced SIMD element or structure load/store instructions. > + // But see ThumbDisassembler::getInstruction(). > + ; > + } > + } else { > + // Table A6-9 32-bit Thumb instruction encoding: Load byte|halfword|word > + return DisassembleThumb2LdSt(true, MI,Opcode,insn,NumOps,NumOpsAdded); > + } > + break; > + case 1: > + if (slice(op2, 4, 4) == 0) { > + // A6.3.12 Data-processing (register) > + return DisassembleThumb2DPReg(MI, Opcode, insn, NumOps, NumOpsAdded); > + } else if (slice(op2, 3, 3) == 0) { > + // A6.3.16 Multiply, multiply accumulate, and absolute difference > + return DisassembleThumb2Mul(MI, Opcode, insn, NumOps, NumOpsAdded); > + } else { > + // A6.3.17 Long multiply, long multiply accumulate, and divide > + return DisassembleThumb2LongMul(MI, Opcode, insn, NumOps, NumOpsAdded); > + } > + break; > + default: > + // FIXME: A6.3.18 Coprocessor instructions > + // But see ThumbDisassembler::getInstruction(). > + ; > + break; > + } > + > + break; > + default: > + assert(0 && "Encoding error for Thumb2 instruction!"); > + break; > + } > + > + return false; > +} > + > +static bool DisassembleThumbFrm(MCInst &MI, unsigned Opcode, uint32_t insn, > + unsigned short NumOps, unsigned &NumOpsAdded) { > + > + uint16_t HalfWord = slice(insn, 31, 16); > + > + if (HalfWord == 0) { > + // A6.2 16-bit Thumb instruction encoding > + // op = bits[15:10] > + uint16_t op = slice(insn, 15, 10); > + return DisassembleThumb1(op, MI, Opcode, insn, NumOps, NumOpsAdded); > + } > + > + unsigned bits15_11 = slice(HalfWord, 15, 11); > + > + // A6.1 Thumb instruction set encoding > + assert((bits15_11 == 0x1D || bits15_11 == 0x1E || bits15_11 == 0x1F) && > + "Bits [15:11] of first halfword of a Thumb2 instruction out of range"); > + > + // A6.3 32-bit Thumb instruction encoding > + > + uint16_t op1 = slice(HalfWord, 12, 11); > + uint16_t op2 = slice(HalfWord, 10, 4); > + uint16_t op = slice(insn, 15, 15); > + > + return DisassembleThumb2(op1, op2, op, MI, Opcode, insn, NumOps, NumOpsAdded); > +} > > Modified: llvm/trunk/lib/Target/ARM/Makefile > URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Target/ARM/Makefile?rev=98637&r1=98636&r2=98637&view=diff > ============================================================================== > --- llvm/trunk/lib/Target/ARM/Makefile (original) > +++ llvm/trunk/lib/Target/ARM/Makefile Tue Mar 16 11:36:54 2010 > @@ -16,8 +16,9 @@ > ARMGenRegisterInfo.inc ARMGenInstrNames.inc \ > ARMGenInstrInfo.inc ARMGenAsmWriter.inc \ > ARMGenDAGISel.inc ARMGenSubtarget.inc \ > - ARMGenCodeEmitter.inc ARMGenCallingConv.inc > + ARMGenCodeEmitter.inc ARMGenCallingConv.inc \ > + ARMGenDisassemblerTables.inc > > -DIRS = AsmPrinter AsmParser TargetInfo > +DIRS = AsmPrinter AsmParser Disassembler TargetInfo > > include $(LEVEL)/Makefile.common > > Modified: llvm/trunk/lib/Target/ARM/Thumb2ITBlockPass.cpp > URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Target/ARM/Thumb2ITBlockPass.cpp?rev=98637&r1=98636&r2=98637&view=diff > ============================================================================== > --- llvm/trunk/lib/Target/ARM/Thumb2ITBlockPass.cpp (original) > +++ llvm/trunk/lib/Target/ARM/Thumb2ITBlockPass.cpp Tue Mar 16 11:36:54 2010 > @@ -78,14 +78,16 @@ > DebugLoc ndl = NMI->getDebugLoc(); > unsigned NPredReg = 0; > ARMCC::CondCodes NCC = getPredicate(NMI, NPredReg); > - if (NCC == OCC) { > - Mask |= (1 << Pos); > - } else if (NCC != CC) > + if (NCC == CC || NCC == OCC) > + Mask |= (NCC & 1) << Pos; > + else > break; > --Pos; > ++MBBI; > } > Mask |= (1 << Pos); > + // Tag along (firstcond[0] << 4) with the mask. > + Mask |= (CC & 1) << 4; > MIB.addImm(Mask); > Modified = true; > ++NumITs; > > Modified: llvm/trunk/test/CodeGen/ARM/2009-10-27-double-align.ll > URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/CodeGen/ARM/2009-10-27-double-align.ll?rev=98637&r1=98636&r2=98637&view=diff > ============================================================================== > --- llvm/trunk/test/CodeGen/ARM/2009-10-27-double-align.ll (original) > +++ llvm/trunk/test/CodeGen/ARM/2009-10-27-double-align.ll Tue Mar 16 11:36:54 2010 > @@ -4,8 +4,8 @@ > > define arm_aapcscc void @g() { > entry: > -;CHECK: [sp, #+8] > -;CHECK: [sp, #+12] > +;CHECK: [sp, #8] > +;CHECK: [sp, #12] > ;CHECK: [sp] > tail call arm_aapcscc void (i8*, ...)* @f(i8* getelementptr ([1 x i8]* @.str, i32 0, i32 0), i32 1, double 2.000000e+00, i32 3, double 4.000000e+00) > ret void > > Modified: llvm/trunk/test/CodeGen/ARM/2009-10-30.ll > URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/CodeGen/ARM/2009-10-30.ll?rev=98637&r1=98636&r2=98637&view=diff > ============================================================================== > --- llvm/trunk/test/CodeGen/ARM/2009-10-30.ll (original) > +++ llvm/trunk/test/CodeGen/ARM/2009-10-30.ll Tue Mar 16 11:36:54 2010 > @@ -6,7 +6,7 @@ > entry: > ;CHECK: sub sp, sp, #4 > ;CHECK: add r{{[0-9]+}}, sp, #8 > -;CHECK: str r{{[0-9]+}}, [sp], #+4 > +;CHECK: str r{{[0-9]+}}, [sp], #4 > ;CHECK: bx lr > %ap = alloca i8*, align 4 > %ap1 = bitcast i8** %ap to i8* > > Modified: llvm/trunk/test/CodeGen/ARM/arm-negative-stride.ll > URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/CodeGen/ARM/arm-negative-stride.ll?rev=98637&r1=98636&r2=98637&view=diff > ============================================================================== > --- llvm/trunk/test/CodeGen/ARM/arm-negative-stride.ll (original) > +++ llvm/trunk/test/CodeGen/ARM/arm-negative-stride.ll Tue Mar 16 11:36:54 2010 > @@ -5,7 +5,7 @@ > > define void @test(i32* %P, i32 %A, i32 %i) nounwind { > entry: > -; CHECK: str r1, [{{r.*}}, +{{r.*}}, lsl #2] > +; CHECK: str r1, [{{r.*}}, {{r.*}}, lsl #2] > icmp eq i32 %i, 0 ; :0 [#uses=1] > br i1 %0, label %return, label %bb > > > Modified: llvm/trunk/test/CodeGen/ARM/globals.ll > URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/CodeGen/ARM/globals.ll?rev=98637&r1=98636&r2=98637&view=diff > ============================================================================== > --- llvm/trunk/test/CodeGen/ARM/globals.ll (original) > +++ llvm/trunk/test/CodeGen/ARM/globals.ll Tue Mar 16 11:36:54 2010 > @@ -41,7 +41,7 @@ > ; DarwinPIC: _test1: > ; DarwinPIC: ldr r0, LCPI1_0 > ; DarwinPIC: LPC1_0: > -; DarwinPIC: ldr r0, [pc, +r0] > +; DarwinPIC: ldr r0, [pc, r0] > ; DarwinPIC: ldr r0, [r0] > ; DarwinPIC: bx lr > > @@ -63,7 +63,7 @@ > > ; LinuxPIC: .LPC1_0: > ; LinuxPIC: add r0, pc, r0 > -; LinuxPIC: ldr r0, [r1, +r0] > +; LinuxPIC: ldr r0, [r1, r0] > ; LinuxPIC: ldr r0, [r0] > ; LinuxPIC: bx lr > > > Modified: llvm/trunk/test/CodeGen/ARM/ldrd.ll > URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/CodeGen/ARM/ldrd.ll?rev=98637&r1=98636&r2=98637&view=diff > ============================================================================== > --- llvm/trunk/test/CodeGen/ARM/ldrd.ll (original) > +++ llvm/trunk/test/CodeGen/ARM/ldrd.ll Tue Mar 16 11:36:54 2010 > @@ -10,10 +10,10 @@ > ;V6: ldrd r2, [r2] > > ;V5: ldr r3, [r2] > -;V5: ldr r2, [r2, #+4] > +;V5: ldr r2, [r2, #4] > > ;EABI: ldr r3, [r2] > -;EABI: ldr r2, [r2, #+4] > +;EABI: ldr r2, [r2, #4] > > %0 = load i64** @b, align 4 > %1 = load i64* %0, align 4 > > Modified: llvm/trunk/test/CodeGen/ARM/str_pre-2.ll > URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/CodeGen/ARM/str_pre-2.ll?rev=98637&r1=98636&r2=98637&view=diff > ============================================================================== > --- llvm/trunk/test/CodeGen/ARM/str_pre-2.ll (original) > +++ llvm/trunk/test/CodeGen/ARM/str_pre-2.ll Tue Mar 16 11:36:54 2010 > @@ -1,5 +1,5 @@ > ; RUN: llc < %s -mtriple=arm-linux-gnu | grep {str.*\\!} > -; RUN: llc < %s -mtriple=arm-linux-gnu | grep {ldr.*\\\[.*\], #+4} > +; RUN: llc < %s -mtriple=arm-linux-gnu | grep {ldr.*\\\[.*\], #4} > > @b = external global i64* > > > Modified: llvm/trunk/test/CodeGen/ARM/tls2.ll > URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/CodeGen/ARM/tls2.ll?rev=98637&r1=98636&r2=98637&view=diff > ============================================================================== > --- llvm/trunk/test/CodeGen/ARM/tls2.ll (original) > +++ llvm/trunk/test/CodeGen/ARM/tls2.ll Tue Mar 16 11:36:54 2010 > @@ -7,7 +7,7 @@ > > define i32 @f() { > ; CHECK-NONPIC: f: > -; CHECK-NONPIC: ldr {{r.}}, [pc, +{{r.}}] > +; CHECK-NONPIC: ldr {{r.}}, [pc, {{r.}}] > ; CHECK-NONPIC: i(gottpoff) > ; CHECK-PIC: f: > ; CHECK-PIC: __tls_get_addr > @@ -18,7 +18,7 @@ > > define i32* @g() { > ; CHECK-NONPIC: g: > -; CHECK-NONPIC: ldr {{r.}}, [pc, +{{r.}}] > +; CHECK-NONPIC: ldr {{r.}}, [pc, {{r.}}] > ; CHECK-NONPIC: i(gottpoff) > ; CHECK-PIC: g: > ; CHECK-PIC: __tls_get_addr > > Modified: llvm/trunk/test/CodeGen/Thumb2/ldr-str-imm12.ll > URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/CodeGen/Thumb2/ldr-str-imm12.ll?rev=98637&r1=98636&r2=98637&view=diff > ============================================================================== > --- llvm/trunk/test/CodeGen/Thumb2/ldr-str-imm12.ll (original) > +++ llvm/trunk/test/CodeGen/Thumb2/ldr-str-imm12.ll Tue Mar 16 11:36:54 2010 > @@ -22,7 +22,7 @@ > > define arm_apcscc %union.rec* @Manifest(%union.rec* %x, %union.rec* %env, %struct.STYLE* %style, %union.rec** %bthr, %union.rec** %fthr, %union.rec** %target, %union.rec** %crs, i32 %ok, i32 %need_expand, %union.rec** %enclose, i32 %fcr) nounwind { > entry: > -; CHECK: ldr.w r9, [r7, #+28] > +; CHECK: ldr.w r9, [r7, #28] > %xgaps.i = alloca [32 x %union.rec*], align 4 ; <[32 x %union.rec*]*> [#uses=0] > %ycomp.i = alloca [32 x %union.rec*], align 4 ; <[32 x %union.rec*]*> [#uses=0] > br i1 false, label %bb, label %bb20 > @@ -50,9 +50,9 @@ > bb420: ; preds = %bb20, %bb20 > ; CHECK: bb420 > ; CHECK: str r{{[0-7]}}, [sp] > -; CHECK: str r{{[0-7]}}, [sp, #+4] > -; CHECK: str r{{[0-7]}}, [sp, #+8] > -; CHECK: str{{(.w)?}} r{{[0-9]+}}, [sp, #+24] > +; CHECK: str r{{[0-7]}}, [sp, #4] > +; CHECK: str r{{[0-7]}}, [sp, #8] > +; CHECK: str{{(.w)?}} r{{[0-9]+}}, [sp, #24] > store %union.rec* null, %union.rec** @zz_hold, align 4 > store %union.rec* null, %union.rec** @zz_res, align 4 > store %union.rec* %x, %union.rec** @zz_hold, align 4 > > Modified: llvm/trunk/test/CodeGen/Thumb2/thumb2-ldr.ll > URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/CodeGen/Thumb2/thumb2-ldr.ll?rev=98637&r1=98636&r2=98637&view=diff > ============================================================================== > --- llvm/trunk/test/CodeGen/Thumb2/thumb2-ldr.ll (original) > +++ llvm/trunk/test/CodeGen/Thumb2/thumb2-ldr.ll Tue Mar 16 11:36:54 2010 > @@ -11,7 +11,7 @@ > define i32 @f2(i32* %v) { > entry: > ; CHECK: f2: > -; CHECK: ldr.w r0, [r0, #+4092] > +; CHECK: ldr.w r0, [r0, #4092] > %tmp2 = getelementptr i32* %v, i32 1023 > %tmp = load i32* %tmp2 > ret i32 %tmp > > Modified: llvm/trunk/test/CodeGen/Thumb2/thumb2-ldrh.ll > URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/CodeGen/Thumb2/thumb2-ldrh.ll?rev=98637&r1=98636&r2=98637&view=diff > ============================================================================== > --- llvm/trunk/test/CodeGen/Thumb2/thumb2-ldrh.ll (original) > +++ llvm/trunk/test/CodeGen/Thumb2/thumb2-ldrh.ll Tue Mar 16 11:36:54 2010 > @@ -11,7 +11,7 @@ > define i16 @f2(i16* %v) { > entry: > ; CHECK: f2: > -; CHECK: ldrh.w r0, [r0, #+2046] > +; CHECK: ldrh.w r0, [r0, #2046] > %tmp2 = getelementptr i16* %v, i16 1023 > %tmp = load i16* %tmp2 > ret i16 %tmp > > Modified: llvm/trunk/test/CodeGen/Thumb2/thumb2-str.ll > URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/CodeGen/Thumb2/thumb2-str.ll?rev=98637&r1=98636&r2=98637&view=diff > ============================================================================== > --- llvm/trunk/test/CodeGen/Thumb2/thumb2-str.ll (original) > +++ llvm/trunk/test/CodeGen/Thumb2/thumb2-str.ll Tue Mar 16 11:36:54 2010 > @@ -9,7 +9,7 @@ > > define i32 @f2(i32 %a, i32* %v) { > ; CHECK: f2: > -; CHECK: str.w r0, [r1, #+4092] > +; CHECK: str.w r0, [r1, #4092] > %tmp2 = getelementptr i32* %v, i32 1023 > store i32 %a, i32* %tmp2 > ret i32 %a > > Modified: llvm/trunk/test/CodeGen/Thumb2/thumb2-str_pre.ll > URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/CodeGen/Thumb2/thumb2-str_pre.ll?rev=98637&r1=98636&r2=98637&view=diff > ============================================================================== > --- llvm/trunk/test/CodeGen/Thumb2/thumb2-str_pre.ll (original) > +++ llvm/trunk/test/CodeGen/Thumb2/thumb2-str_pre.ll Tue Mar 16 11:36:54 2010 > @@ -2,7 +2,7 @@ > > define void @test1(i32* %X, i32* %A, i32** %dest) { > ; CHECK: test1 > -; CHECK: str r1, [r0, #+16]! > +; CHECK: str r1, [r0, #16]! > %B = load i32* %A ; [#uses=1] > %Y = getelementptr i32* %X, i32 4 ; [#uses=2] > store i32 %B, i32* %Y > @@ -12,7 +12,7 @@ > > define i16* @test2(i16* %X, i32* %A) { > ; CHECK: test2 > -; CHECK: strh r1, [r0, #+8]! > +; CHECK: strh r1, [r0, #8]! > %B = load i32* %A ; [#uses=1] > %Y = getelementptr i16* %X, i32 4 ; [#uses=2] > %tmp = trunc i32 %B to i16 ; [#uses=1] > > Modified: llvm/trunk/test/CodeGen/Thumb2/thumb2-strb.ll > URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/CodeGen/Thumb2/thumb2-strb.ll?rev=98637&r1=98636&r2=98637&view=diff > ============================================================================== > --- llvm/trunk/test/CodeGen/Thumb2/thumb2-strb.ll (original) > +++ llvm/trunk/test/CodeGen/Thumb2/thumb2-strb.ll Tue Mar 16 11:36:54 2010 > @@ -9,7 +9,7 @@ > > define i8 @f2(i8 %a, i8* %v) { > ; CHECK: f2: > -; CHECK: strb.w r0, [r1, #+4092] > +; CHECK: strb.w r0, [r1, #4092] > %tmp2 = getelementptr i8* %v, i32 4092 > store i8 %a, i8* %tmp2 > ret i8 %a > > Modified: llvm/trunk/test/CodeGen/Thumb2/thumb2-strh.ll > URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/CodeGen/Thumb2/thumb2-strh.ll?rev=98637&r1=98636&r2=98637&view=diff > ============================================================================== > --- llvm/trunk/test/CodeGen/Thumb2/thumb2-strh.ll (original) > +++ llvm/trunk/test/CodeGen/Thumb2/thumb2-strh.ll Tue Mar 16 11:36:54 2010 > @@ -9,7 +9,7 @@ > > define i16 @f2(i16 %a, i16* %v) { > ; CHECK: f2: > -; CHECK: strh.w r0, [r1, #+4092] > +; CHECK: strh.w r0, [r1, #4092] > %tmp2 = getelementptr i16* %v, i32 2046 > store i16 %a, i16* %tmp2 > ret i16 %a > > Modified: llvm/trunk/utils/TableGen/DisassemblerEmitter.cpp > URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/utils/TableGen/DisassemblerEmitter.cpp?rev=98637&r1=98636&r2=98637&view=diff > ============================================================================== > --- llvm/trunk/utils/TableGen/DisassemblerEmitter.cpp (original) > +++ llvm/trunk/utils/TableGen/DisassemblerEmitter.cpp Tue Mar 16 11:36:54 2010 > @@ -12,6 +12,8 @@ > #include "Record.h" > #include "X86DisassemblerTables.h" > #include "X86RecognizableInstr.h" > +#include "RISCDisassemblerEmitter.h" > + > using namespace llvm; > using namespace llvm::X86Disassembler; > > @@ -124,6 +126,12 @@ > return; > } > > + // Fixed-instruction-length targets use a common disassembler. > + if (Target.getName() == "ARM") { > + RISCDisassemblerEmitter(Records).run(OS); > + return; > + } > + > throw TGError(Target.getTargetRecord()->getLoc(), > "Unable to generate disassembler for this target"); > } > > Added: llvm/trunk/utils/TableGen/RISCDisassemblerEmitter.cpp > URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/utils/TableGen/RISCDisassemblerEmitter.cpp?rev=98637&view=auto > ============================================================================== > --- llvm/trunk/utils/TableGen/RISCDisassemblerEmitter.cpp (added) > +++ llvm/trunk/utils/TableGen/RISCDisassemblerEmitter.cpp Tue Mar 16 11:36:54 2010 > @@ -0,0 +1,1743 @@ > +//===- RISCDisassemblerEmitter.cpp - Disassembler Generator ---------------===// > +// > +// The LLVM Compiler Infrastructure > +// > +// This file is distributed under the University of Illinois Open Source > +// License. See LICENSE.TXT for details. > +// > +//===----------------------------------------------------------------------===// > +// > +// FIXME: document > +// > +//===----------------------------------------------------------------------===// > + > +#define DEBUG_TYPE "risc-disassembler-emitter" > + > +#include "RISCDisassemblerEmitter.h" > +#include "CodeGenTarget.h" > +#include "Record.h" > +#include "llvm/ADT/StringExtras.h" > +#include "llvm/Support/Debug.h" > +#include "llvm/Support/raw_ostream.h" > + > +#include > +#include > +#include > +#include > +#include > +#include > + > +using namespace llvm; > + > +//////////////////////////////////// > +// Utility classes / structures // > +//////////////////////////////////// > + > +// LLVM coding style > +#define INDENT_LEVEL 2 > + > +/// Indenter - A little helper class to keep track of the indentation depth, > +/// while the instance object is being passed around. > +class Indenter { > +public: > + Indenter() : depth(0) {} > + > + void push() { > + depth += INDENT_LEVEL; > + } > + > + void pop() { > + if (depth >= INDENT_LEVEL) > + depth -= INDENT_LEVEL; > + } > + > + // Conversion operator. > + operator int () { > + return depth; > + } > +private: > + uint8_t depth; > +}; > + > +///////////////////////// > +// Utility functions // > +///////////////////////// > + > +static uint8_t byteFromBitsInit(BitsInit &init) { > + int width = init.getNumBits(); > + > + assert(width <= 8 && "Field is too large for uint8_t!"); > + > + int index; > + uint8_t mask = 0x01; > + > + uint8_t ret = 0; > + > + for (index = 0; index < width; index++) { > + if (static_cast(init.getBit(index))->getValue()) > + ret |= mask; > + > + mask <<= 1; > + } > + > + return ret; > +} > + > +static uint8_t getByteField(const Record &def, const char *str) { > + BitsInit *bits = def.getValueAsBitsInit(str); > + return byteFromBitsInit(*bits); > +} > + > +static BitsInit &getBitsField(const Record &def, const char *str) { > + BitsInit *bits = def.getValueAsBitsInit(str); > + return *bits; > +} > + > +/// sameStringExceptEndingChar - Return true if the two strings differ only in > +/// the ending char. ("VST4q8a", "VST4q8b", 'a', 'b') as input returns true. > +static > +bool sameStringExceptEndingChar(const std::string &LHS, const std::string &RHS, > + char lhc, char rhc) { > + > + if (LHS.length() > 1 && RHS.length() > 1 && LHS.length() == RHS.length()) { > + unsigned length = LHS.length(); > + return LHS.substr(0, length - 1) == RHS.substr(0, length - 1) > + && LHS[length - 1] == lhc && RHS[length - 1] == rhc; > + } > + > + return false; > +} > + > +/// thumbInstruction - Determine whether we have a Thumb instruction. > +/// See also ARMInstrFormats.td. > +static bool thumbInstruction(uint8_t Form) { > + return Form == 23; > +} > + > +// The set (BIT_TRUE, BIT_FALSE, BIT_UNSET) represents a ternary logic system > +// for a bit value. > +// > +// BIT_UNFILTERED is used as the init value for a filter position. It is used > +// only for filter processings. > +typedef enum { > + BIT_TRUE, // '1' > + BIT_FALSE, // '0' > + BIT_UNSET, // '?' > + BIT_UNFILTERED // unfiltered > +} bit_value_t; > + > +static bit_value_t bitFromBits(BitsInit &bits, unsigned index) { > + if (BitInit *bit = dynamic_cast(bits.getBit(index))) > + return bit->getValue() ? BIT_TRUE : BIT_FALSE; > + > + // The bit is uninitialized. > + return BIT_UNSET; > +} > + > +static void dumpBits(raw_ostream &o, BitsInit &bits) { > + unsigned index; > + > + for (index = bits.getNumBits(); index > 0; index--) { > + switch (bitFromBits(bits, index - 1)) { > + case BIT_TRUE: > + o << "1"; > + break; > + case BIT_FALSE: > + o << "0"; > + break; > + case BIT_UNSET: > + o << "_"; > + break; > + default: > + assert(0 && "unexpected return value from bitFromBits"); > + } > + } > +} > + > +///////////// > +// Enums // > +///////////// > + > +#define ARM_FORMATS \ > + ENTRY(ARM_FORMAT_PSEUDO, 0) \ > + ENTRY(ARM_FORMAT_MULFRM, 1) \ > + ENTRY(ARM_FORMAT_BRFRM, 2) \ > + ENTRY(ARM_FORMAT_BRMISCFRM, 3) \ > + ENTRY(ARM_FORMAT_DPFRM, 4) \ > + ENTRY(ARM_FORMAT_DPSOREGFRM, 5) \ > + ENTRY(ARM_FORMAT_LDFRM, 6) \ > + ENTRY(ARM_FORMAT_STFRM, 7) \ > + ENTRY(ARM_FORMAT_LDMISCFRM, 8) \ > + ENTRY(ARM_FORMAT_STMISCFRM, 9) \ > + ENTRY(ARM_FORMAT_LDSTMULFRM, 10) \ > + ENTRY(ARM_FORMAT_ARITHMISCFRM, 11) \ > + ENTRY(ARM_FORMAT_EXTFRM, 12) \ > + ENTRY(ARM_FORMAT_VFPUNARYFRM, 13) \ > + ENTRY(ARM_FORMAT_VFPBINARYFRM, 14) \ > + ENTRY(ARM_FORMAT_VFPCONV1FRM, 15) \ > + ENTRY(ARM_FORMAT_VFPCONV2FRM, 16) \ > + ENTRY(ARM_FORMAT_VFPCONV3FRM, 17) \ > + ENTRY(ARM_FORMAT_VFPCONV4FRM, 18) \ > + ENTRY(ARM_FORMAT_VFPCONV5FRM, 19) \ > + ENTRY(ARM_FORMAT_VFPLDSTFRM, 20) \ > + ENTRY(ARM_FORMAT_VFPLDSTMULFRM, 21) \ > + ENTRY(ARM_FORMAT_VFPMISCFRM, 22) \ > + ENTRY(ARM_FORMAT_THUMBFRM, 23) \ > + ENTRY(ARM_FORMAT_NEONFRM, 24) \ > + ENTRY(ARM_FORMAT_NEONGETLNFRM, 25) \ > + ENTRY(ARM_FORMAT_NEONSETLNFRM, 26) \ > + ENTRY(ARM_FORMAT_NEONDUPFRM, 27) \ > + ENTRY(ARM_FORMAT_LDSTEXFRM, 28) \ > + ENTRY(ARM_FORMAT_MISCFRM, 29) \ > + ENTRY(ARM_FORMAT_THUMBMISCFRM, 30) > + > +// ARM instruction format specifies the encoding used by the instruction. > +#define ENTRY(n, v) n = v, > +typedef enum { > + ARM_FORMATS > + ARM_FORMAT_NA > +} ARMFormat; > +#undef ENTRY > + > +// Converts enum to const char*. > +static const char *stringForARMFormat(ARMFormat form) { > +#define ENTRY(n, v) case n: return #n; > + switch(form) { > + ARM_FORMATS > + case ARM_FORMAT_NA: > + default: > + return ""; > + } > +#undef ENTRY > +} > + > +#define NS_FORMATS \ > + ENTRY(NS_FORMAT_NONE, 0) \ > + ENTRY(NS_FORMAT_VLDSTLane, 1) \ > + ENTRY(NS_FORMAT_VLDSTLaneDbl, 2) \ > + ENTRY(NS_FORMAT_VLDSTRQ, 3) \ > + ENTRY(NS_FORMAT_NVdImm, 4) \ > + ENTRY(NS_FORMAT_NVdVmImm, 5) \ > + ENTRY(NS_FORMAT_NVdVmImmVCVT, 6) \ > + ENTRY(NS_FORMAT_NVdVmImmVDupLane, 7) \ > + ENTRY(NS_FORMAT_NVdVmImmVSHLL, 8) \ > + ENTRY(NS_FORMAT_NVectorShuffle, 9) \ > + ENTRY(NS_FORMAT_NVectorShift, 10) \ > + ENTRY(NS_FORMAT_NVectorShift2, 11) \ > + ENTRY(NS_FORMAT_NVdVnVmImm, 12) \ > + ENTRY(NS_FORMAT_NVdVnVmImmVectorShift, 13) \ > + ENTRY(NS_FORMAT_NVdVnVmImmVectorExtract, 14) \ > + ENTRY(NS_FORMAT_NVdVnVmImmMulScalar, 15) \ > + ENTRY(NS_FORMAT_VTBL, 16) > + > +// NEON instruction sub-format further classify the NEONFrm instruction. > +#define ENTRY(n, v) n = v, > +typedef enum { > + NS_FORMATS > + NS_FORMAT_NA > +} NSFormat; > +#undef ENTRY > + > +// Converts enum to const char*. > +static const char *stringForNSFormat(NSFormat form) { > +#define ENTRY(n, v) case n: return #n; > + switch(form) { > + NS_FORMATS > + case NS_FORMAT_NA: > + default: > + return ""; > + } > +#undef ENTRY > +} > + > +// Enums for the available target names. > +typedef enum { > + TARGET_ARM = 0, > + TARGET_THUMB > +} TARGET_NAME_t; > + > +class AbstractFilterChooser { > +public: > + static TARGET_NAME_t TargetName; > + static void setTargetName(TARGET_NAME_t tn) { TargetName = tn; } > + virtual ~AbstractFilterChooser() {} > + virtual void emitTop(raw_ostream &o, Indenter &i) = 0; > + virtual void emitBot(raw_ostream &o, Indenter &i) = 0; > +}; > + > +// Define the symbol here. > +TARGET_NAME_t AbstractFilterChooser::TargetName; > + > +template > +class FilterChooser : public AbstractFilterChooser { > +protected: > + // Representation of the instruction to work on. > + typedef bit_value_t insn_t[tBitWidth]; > + > + class Filter { > + protected: > + FilterChooser *Owner; // pointer without ownership > + unsigned StartBit; // the starting bit position > + unsigned NumBits; // number of bits to filter > + bool Mixed; // a mixed region contains both set and unset bits > + > + // Map of well-known segment value to the set of uid's with that value. > + std::map > FilteredInstructions; > + > + // Set of uid's with non-constant segment values. > + std::vector VariableInstructions; > + > + // Map of well-known segment value to its delegate. > + std::map FilterChooserMap; > + > + // Number of instructions which fall under FilteredInstructions category. > + unsigned NumFiltered; > + > + // Keeps track of the last opcode in the filtered bucket. > + unsigned LastOpcFiltered; > + > + // Number of instructions which fall under VariableInstructions category. > + unsigned NumVariable; > + > + public: > + unsigned getNumFiltered() { return NumFiltered; } > + unsigned getNumVariable() { return NumVariable; } > + unsigned getSingletonOpc() { > + assert(NumFiltered == 1); > + return LastOpcFiltered; > + } > + FilterChooser &getVariableFC() { > + assert(NumFiltered == 1); > + assert(FilterChooserMap.size() == 1); > + return FilterChooserMap.find(-1)->second; > + } > + > + Filter(const Filter &f) : > + Owner(f.Owner), > + StartBit(f.StartBit), > + NumBits(f.NumBits), > + Mixed(f.Mixed), > + FilteredInstructions(f.FilteredInstructions), > + VariableInstructions(f.VariableInstructions), > + FilterChooserMap(f.FilterChooserMap), > + NumFiltered(f.NumFiltered), > + LastOpcFiltered(f.LastOpcFiltered), > + NumVariable(f.NumVariable) { } > + > + Filter(FilterChooser &owner, unsigned startBit, unsigned numBits, > + bool mixed) : > + Owner(&owner), > + StartBit(startBit), > + NumBits(numBits), > + Mixed(mixed) > + { > + assert(StartBit + NumBits - 1 < tBitWidth); > + > + NumFiltered = 0; > + LastOpcFiltered = 0; > + NumVariable = 0; > + > + for (unsigned i = 0, e = Owner->Opcodes.size(); i != e; ++i) { > + insn_t Insn; > + > + // Populates the insn given the uid. > + Owner->insnWithID(Insn, Owner->Opcodes[i]); > + > + uint64_t Field; > + // Scans the segment for possibly well-specified encoding bits. > + bool ok = Owner->fieldFromInsn(Field, Insn, StartBit, NumBits); > + > + if (ok) { > + // The encoding bits are well-known. Lets add the uid of the > + // instruction into the bucket keyed off the constant field value. > + LastOpcFiltered = Owner->Opcodes[i]; > + FilteredInstructions[Field].push_back(LastOpcFiltered); > + ++NumFiltered; > + } else { > + // Some of the encoding bit(s) are unspecfied. This contributes to > + // one additional member of "Variable" instructions. > + VariableInstructions.push_back(Owner->Opcodes[i]); > + ++NumVariable; > + } > + } > + > + assert((FilteredInstructions.size() + VariableInstructions.size() > 0) > + && "Filter returns no instruction categories"); > + } > + > + // Divides the decoding task into sub tasks and delegates them to the > + // inferior FilterChooser's. > + // > + // A special case arises when there's only one entry in the filtered > + // instructions. In order to unambiguously decode the singleton, we need to > + // match the remaining undecoded encoding bits against the singleton. > + void recurse() { > + std::map >::const_iterator mapIterator; > + > + bit_value_t BitValueArray[tBitWidth]; > + // Starts by inheriting our parent filter chooser's filter bit values. > + memcpy(BitValueArray, Owner->FilterBitValues, sizeof(BitValueArray)); > + > + unsigned bitIndex; > + > + if (VariableInstructions.size()) { > + // Conservatively marks each segment position as BIT_UNSET. > + for (bitIndex = 0; bitIndex < NumBits; bitIndex++) > + BitValueArray[StartBit + bitIndex] = BIT_UNSET; > + > + // Delegates to an inferior filter chooser for futher processing on this > + // group of instructions whose segment values are variable. > + FilterChooserMap.insert(std::pair( > + (unsigned)-1, > + FilterChooser(Owner->AllInstructions, > + VariableInstructions, > + BitValueArray, > + *Owner) > + )); > + } > + > + // No need to recurse for a singleton filtered instruction. > + // See also Filter::emit(). > + if (getNumFiltered() == 1) { > + //Owner->SingletonExists(LastOpcFiltered); > + assert(FilterChooserMap.size() == 1); > + return; > + } > + > + // Otherwise, create sub choosers. > + for (mapIterator = FilteredInstructions.begin(); > + mapIterator != FilteredInstructions.end(); > + mapIterator++) { > + > + // Marks all the segment positions with either BIT_TRUE or BIT_FALSE. > + for (bitIndex = 0; bitIndex < NumBits; bitIndex++) { > + if (mapIterator->first & (1 << bitIndex)) > + BitValueArray[StartBit + bitIndex] = BIT_TRUE; > + else > + BitValueArray[StartBit + bitIndex] = BIT_FALSE; > + } > + > + // Delegates to an inferior filter chooser for futher processing on this > + // category of instructions. > + FilterChooserMap.insert(std::pair( > + mapIterator->first, > + FilterChooser(Owner->AllInstructions, > + mapIterator->second, > + BitValueArray, > + *Owner) > + )); > + } > + } > + > + // Emit code to decode instructions given a segment or segments of bits. > + void emit(raw_ostream &o, Indenter &i) { > + o.indent(i) << "// Check Inst{"; > + > + if (NumBits > 1) > + o << (StartBit + NumBits - 1) << '-'; > + > + o << StartBit << "} ...\n"; > + > + o.indent(i) << "switch (fieldFromInstruction(insn, " > + << StartBit << ", " << NumBits << ")) {\n"; > + > + typename std::map::iterator filterIterator; > + > + bool DefaultCase = false; > + for (filterIterator = FilterChooserMap.begin(); > + filterIterator != FilterChooserMap.end(); > + filterIterator++) { > + > + // Field value -1 implies a non-empty set of variable instructions. > + // See also recurse(). > + if (filterIterator->first == (unsigned)-1) { > + DefaultCase = true; > + > + o.indent(i) << "default:\n"; > + o.indent(i) << " break; // fallthrough\n"; > + > + // Closing curly brace for the switch statement. > + // This is unconventional because we want the default processing to be > + // performed for the fallthrough cases as well, i.e., when the "cases" > + // did not prove a decoded instruction. > + o.indent(i) << "}\n"; > + > + } else { > + o.indent(i) << "case " << filterIterator->first << ":\n"; > + } > + > + // We arrive at a category of instructions with the same segment value. > + // Now delegate to the sub filter chooser for further decodings. > + // The case may fallthrough, which happens if the remaining well-known > + // encoding bits do not match exactly. > + if (!DefaultCase) i.push(); > + { > + bool finished = filterIterator->second.emit(o, i); > + // For top level default case, there's no need for a break statement. > + if (Owner->isTopLevel() && DefaultCase) > + break; > + if (!finished) > + o.indent(i) << "break;\n"; > + } > + if (!DefaultCase) i.pop(); > + } > + > + // If there is no default case, we still need to supply a closing brace. > + if (!DefaultCase) { > + // Closing curly brace for the switch statement. > + o.indent(i) << "}\n"; > + } > + } > + > + // Returns the number of fanout produced by the filter. More fanout implies > + // the filter distinguishes more categories of instructions. > + unsigned usefulness() const { > + if (VariableInstructions.size()) > + return FilteredInstructions.size(); > + else > + return FilteredInstructions.size() + 1; > + } > + }; // End of inner class Filter > + > + friend class Filter; > + > + // Vector of codegen instructions to choose our filter. > + const std::vector &AllInstructions; > + > + // Vector of uid's for this filter chooser to work on. > + const std::vector Opcodes; > + > + // Vector of candidate filters. > + std::vector Filters; > + > + // Array of bit values passed down from our parent. > + // Set to all BIT_UNFILTERED's for Parent == NULL. > + bit_value_t FilterBitValues[tBitWidth]; > + > + // Links to the FilterChooser above us in the decoding tree. > + FilterChooser *Parent; > + > + // Index of the best filter from Filters. > + int BestIndex; > + > +public: > + FilterChooser(const FilterChooser &FC) : > + AbstractFilterChooser(), > + AllInstructions(FC.AllInstructions), > + Opcodes(FC.Opcodes), > + Filters(FC.Filters), > + Parent(FC.Parent), > + BestIndex(FC.BestIndex) > + { > + memcpy(FilterBitValues, FC.FilterBitValues, sizeof(FilterBitValues)); > + } > + > + FilterChooser(const std::vector &Insts, > + const std::vector &IDs) : > + AllInstructions(Insts), > + Opcodes(IDs), > + Filters(), > + Parent(NULL), > + BestIndex(-1) > + { > + for (unsigned i = 0; i < tBitWidth; ++i) > + FilterBitValues[i] = BIT_UNFILTERED; > + > + doFilter(); > + } > + > + FilterChooser(const std::vector &Insts, > + const std::vector &IDs, > + bit_value_t (&ParentFilterBitValues)[tBitWidth], > + FilterChooser &parent) : > + AllInstructions(Insts), > + Opcodes(IDs), > + Filters(), > + Parent(&parent), > + BestIndex(-1) > + { > + for (unsigned i = 0; i < tBitWidth; ++i) > + FilterBitValues[i] = ParentFilterBitValues[i]; > + > + doFilter(); > + } > + > + // The top level filter chooser has NULL as its parent. > + bool isTopLevel() { return Parent == NULL; } > + > + // This provides an opportunity for target specific code emission. > + void emitTopHook(raw_ostream &o, Indenter &i) { > + if (TargetName == TARGET_ARM) { > + // Emit code that references the ARMFormat data type. > + o << "static const ARMFormat ARMFormats[] = {\n"; > + for (unsigned i = 0, e = AllInstructions.size(); i != e; ++i) { > + const Record &Def = *(AllInstructions[i]->TheDef); > + const std::string &Name = Def.getName(); > + if (Def.isSubClassOf("InstARM") || Def.isSubClassOf("InstThumb")) > + o.indent(2) << > + stringForARMFormat((ARMFormat)getByteField(Def, "Form")); > + else > + o << " ARM_FORMAT_NA"; > + > + o << ",\t// Inst #" << i << " = " << Name << '\n'; > + } > + o << " ARM_FORMAT_NA\t// Unreachable.\n"; > + o << "};\n\n"; > + > + // And emit code that references the NSFormat data type. > + // This is meaningful only for NEONFrm instructions. > + o << "static const NSFormat NSFormats[] = {\n"; > + for (unsigned i = 0, e = AllInstructions.size(); i != e; ++i) { > + const Record &Def = *(AllInstructions[i]->TheDef); > + const std::string &Name = Def.getName(); > + if (Def.isSubClassOf("NeonI") || Def.isSubClassOf("NeonXI")) > + o.indent(2) << > + stringForNSFormat((NSFormat)getByteField(Def, "NSForm")); > + else > + o << " NS_FORMAT_NA"; > + > + o << ",\t// Inst #" << i << " = " << Name << '\n'; > + } > + o << " NS_FORMAT_NA\t// Unreachable.\n"; > + o << "};\n\n"; > + } > + } > + > + // Emit the top level typedef and decodeInstruction() function. > + void emitTop(raw_ostream &o, Indenter &i) { > + > + // Run the target specific emit hook. > + emitTopHook(o, i); > + > + switch(tBitWidth) { > + case 8: > + o.indent(i) << "typedef uint8_t field_t;\n"; > + break; > + case 16: > + o.indent(i) << "typedef uint16_t field_t;\n"; > + break; > + case 32: > + o.indent(i) << "typedef uint32_t field_t;\n"; > + break; > + case 64: > + o.indent(i) << "typedef uint64_t field_t;\n"; > + break; > + default: > + assert(0 && "Unexpected instruction size!"); > + } > + > + o << '\n'; > + > + o.indent(i) << "static field_t " << > + "fieldFromInstruction(field_t insn, unsigned startBit, unsigned numBits)\n"; > + > + o.indent(i) << "{\n"; > + i.push(); > + { > + o.indent(i) << "assert(startBit + numBits <= " << tBitWidth > + << " && \"Instruction field out of bounds!\");\n"; > + o << '\n'; > + o.indent(i) << "field_t fieldMask;\n"; > + o << '\n'; > + o.indent(i) << "if (numBits == " << tBitWidth << ")\n"; > + > + i.push(); > + { > + o.indent(i) << "fieldMask = (field_t)-1;\n"; > + } > + i.pop(); > + > + o.indent(i) << "else\n"; > + > + i.push(); > + { > + o.indent(i) << "fieldMask = ((1 << numBits) - 1) << startBit;\n"; > + } > + i.pop(); > + > + o << '\n'; > + o.indent(i) << "return (insn & fieldMask) >> startBit;\n"; > + } > + i.pop(); > + o.indent(i) << "}\n"; > + > + o << '\n'; > + > + o.indent(i) << "static uint16_t decodeInstruction(field_t insn) {\n"; > + > + i.push(); > + { > + // Emits code to decode the instructions. > + emit(o, i); > + > + o << '\n'; > + o.indent(i) << "return 0;\n"; > + } > + i.pop(); > + > + o.indent(i) << "}\n"; > + > + o << '\n'; > + > + } > + > + // This provides an opportunity for target specific code emission after > + // emitTop(). > + void emitBot(raw_ostream &o, Indenter &i) { > + if (TargetName == TARGET_THUMB) { > + // Emit code that decodes the Thumb ISA. > + o.indent(i) > + << "static uint16_t decodeThumbInstruction(field_t insn) {\n"; > + > + i.push(); > + { > + // Emits code to decode the instructions. > + emit(o, i); > + > + o << '\n'; > + o.indent(i) << "return 0;\n"; > + } > + i.pop(); > + > + o.indent(i) << "}\n"; > + } > + } > + > +protected: > + // Populates the insn given the uid. > + void insnWithID(insn_t &Insn, unsigned Opcode) const { > + assert(Opcode > 10); > + BitsInit &Bits = getBitsField(*AllInstructions[Opcode]->TheDef, "Inst"); > + > + for (unsigned i = 0; i < tBitWidth; ++i) > + Insn[i] = bitFromBits(Bits, i); > + } > + > + // Returns the record name. > + const std::string &nameWithID(unsigned Opcode) const { > + return AllInstructions[Opcode]->TheDef->getName(); > + } > + > + // Populates the field of the insn given the start position and the number of > + // consecutive bits to scan for. > + // > + // Returns false if and on the first uninitialized bit value encountered. > + // Returns true, otherwise. > + const bool fieldFromInsn(uint64_t &Field, insn_t &Insn, unsigned StartBit, > + unsigned NumBits) const { > + Field = 0; > + > + for (unsigned i = 0; i < NumBits; ++i) { > + if (Insn[StartBit + i] == BIT_UNSET) > + return false; > + > + if (Insn[StartBit + i] == BIT_TRUE) > + Field = Field | (1 << i); > + } > + > + return true; > + } > + > + void dumpFilterArray(raw_ostream &o, bit_value_t (&filter)[tBitWidth]) { > + unsigned bitIndex; > + > + for (bitIndex = tBitWidth; bitIndex > 0; bitIndex--) { > + switch (filter[bitIndex - 1]) { > + case BIT_UNFILTERED: > + o << "."; > + break; > + case BIT_UNSET: > + o << "_"; > + break; > + case BIT_TRUE: > + o << "1"; > + break; > + case BIT_FALSE: > + o << "0"; > + break; > + } > + } > + } > + > + void dumpStack(raw_ostream &o, const char *prefix) { > + FilterChooser *current = this; > + > + while (current) { > + o << prefix; > + > + dumpFilterArray(o, current->FilterBitValues); > + > + o << '\n'; > + > + current = current->Parent; > + } > + } > + > + Filter &bestFilter() { > + assert(BestIndex != -1 && "BestIndex not set"); > + return Filters[BestIndex]; > + } > + > + // States of our finite state machines. > + typedef enum { > + ATTR_NONE, > + ATTR_FILTERED, > + ATTR_ALL_SET, > + ATTR_ALL_UNSET, > + ATTR_MIXED > + } bitAttr_t; > + > + // Called from Filter::recurse() when singleton exists. For debug purpose. > + void SingletonExists(unsigned Opc) { > + > + insn_t Insn0; > + insnWithID(Insn0, Opc); > + > + errs() << "Singleton exists: " << nameWithID(Opc) > + << " with its decoding dominating "; > + for (unsigned i = 0; i < Opcodes.size(); ++i) { > + if (Opcodes[i] == Opc) continue; > + errs() << nameWithID(Opcodes[i]) << ' '; > + } > + errs() << '\n'; > + > + dumpStack(errs(), "\t\t"); > + for (unsigned i = 0; i < Opcodes.size(); i++) { > + const std::string &Name = nameWithID(Opcodes[i]); > + > + errs() << '\t' << Name << " "; > + dumpBits(errs(), > + getBitsField(*AllInstructions[Opcodes[i]]->TheDef, "Inst")); > + errs() << '\n'; > + } > + } > + > + bool ValueSet(bit_value_t V) { > + return (V == BIT_TRUE || V == BIT_FALSE); > + } > + bool ValueNotSet(bit_value_t V) { > + return (V == BIT_UNSET); > + } > + int Value(bit_value_t V) { > + return ValueNotSet(V) ? -1 : (V == BIT_FALSE ? 0 : 1); > + } > + bool PositionFiltered(unsigned i) { > + return ValueSet(FilterBitValues[i]); > + } > + > + // Calculates the island(s) needed to decode the instruction. > + unsigned getIslands(std::vector &StartBits, > + std::vector &EndBits, > + std::vector &FieldVals, insn_t &Insn) > + { > + unsigned Num, BitNo; > + Num = BitNo = 0; > + > + uint64_t FieldVal = 0; > + > + // 0: Init > + // 1: Water > + // 2: Island > + int State = 0; > + int Val = -1; > + > + for (unsigned i = 0; i < tBitWidth; ++i) { > + Val = Value(Insn[i]); > + bool Filtered = PositionFiltered(i); > + switch (State) { > + default: > + assert(0 && "Unreachable code!"); > + break; > + case 0: > + case 1: > + if (Filtered || Val == -1) > + State = 1; // Still in Water > + else { > + State = 2; // Into the Island > + BitNo = 0; > + StartBits.push_back(i); > + FieldVal = Val; > + } > + break; > + case 2: > + if (Filtered || Val == -1) { > + State = 1; // Into the Water > + EndBits.push_back(i - 1); > + FieldVals.push_back(FieldVal); > + ++Num; > + } else { > + State = 2; // Still in Island > + ++BitNo; > + FieldVal = FieldVal | Val << BitNo; > + } > + break; > + } > + } > + // If we are still in Island after the loop, do some housekeeping. > + if (State == 2) { > + EndBits.push_back(tBitWidth - 1); > + FieldVals.push_back(FieldVal); > + ++Num; > + } > + > + /* > + printf("StartBits.size()=%u,EndBits.size()=%u,FieldVals.size()=%u,Num=%u\n", > + (unsigned)StartBits.size(), (unsigned)EndBits.size(), > + (unsigned)FieldVals.size(), Num); > + */ > + > + assert(StartBits.size() == Num && EndBits.size() == Num && > + FieldVals.size() == Num); > + > + return Num; > + } > + > + bool LdStCopEncoding1(unsigned Opc) { > + const std::string &Name = nameWithID(Opc); > + if (Name == "LDC_OFFSET" || Name == "LDC_OPTION" || > + Name == "LDC_POST" || Name == "LDC_PRE" || > + Name == "LDCL_OFFSET" || Name == "LDCL_OPTION" || > + Name == "LDCL_POST" || Name == "LDCL_PRE" || > + Name == "STC_OFFSET" || Name == "STC_OPTION" || > + Name == "STC_POST" || Name == "STC_PRE" || > + Name == "STCL_OFFSET" || Name == "STCL_OPTION" || > + Name == "STCL_POST" || Name == "STCL_PRE") > + return true; > + else > + return false; > + } > + > + // Emits code to decode the singleton. Return true if we have matched all the > + // well-known bits. > + bool emitSingletonDecoder(raw_ostream &o, Indenter &i, unsigned Opc) { > + > + std::vector StartBits; > + std::vector EndBits; > + std::vector FieldVals; > + insn_t Insn; > + insnWithID(Insn, Opc); > + > + if (TargetName == TARGET_ARM && LdStCopEncoding1(Opc)) { > + o.indent(i); > + // A8.6.51 & A8.6.188 > + // If coproc = 0b101?, i.e, slice(insn, 11, 8) = 10 or 11, escape. > + o << "if (fieldFromInstruction(insn, 9, 3) == 5) break; // fallthrough\n"; > + } > + > + // Look for islands of undecoded bits of the singleton. > + getIslands(StartBits, EndBits, FieldVals, Insn); > + > + unsigned Size = StartBits.size(); > + unsigned I, NumBits; > + > + // If we have matched all the well-known bits, just issue a return. > + if (Size == 0) { > + o.indent(i) << "return " << Opc << "; // " << nameWithID(Opc) << '\n'; > + return true; > + } > + > + // Otherwise, there are more decodings to be done! > + > + // Emit code to match the island(s) for the singleton. > + o.indent(i) << "// Check "; > + > + for (I = Size; I != 0; --I) { > + o << "Inst{" << EndBits[I-1] << '-' << StartBits[I-1] << "} "; > + if (I > 1) > + o << "&& "; > + else > + o << "for singleton decoding...\n"; > + } > + > + o.indent(i) << "if ("; > + > + for (I = Size; I != 0; --I) { > + NumBits = EndBits[I-1] - StartBits[I-1] + 1; > + o << "fieldFromInstruction(insn, " << StartBits[I-1] << ", " << NumBits > + << ") == " << FieldVals[I-1]; > + if (I > 1) > + o << " && "; > + else > + o << ")\n"; > + } > + > + o.indent(i) << " return " << Opc << "; // " << nameWithID(Opc) << '\n'; > + > + return false; > + } > + > + // Emits code to decode the singleton, and then to decode the rest. > + void emitSingletonDecoder(raw_ostream &o, Indenter &i, Filter & Best) { > + > + unsigned Opc = Best.getSingletonOpc(); > + > + emitSingletonDecoder(o, i, Opc); > + > + // Emit code for the rest. > + o.indent(i) << "else\n"; > + i.push(); > + { > + Best.getVariableFC().emit(o, i); > + } > + i.pop(); > + } > + > + // Assign a single filter and run with it. > + void runSingleFilter(FilterChooser &owner, unsigned startBit, unsigned numBit, > + bool mixed) { > + Filters.clear(); > + Filter F(*this, startBit, numBit, true); > + Filters.push_back(F); > + BestIndex = 0; // Sole Filter instance to choose from. > + bestFilter().recurse(); > + } > + > + bool filterProcessor(bool AllowMixed, bool Greedy = true) { > + Filters.clear(); > + BestIndex = -1; > + unsigned numInstructions = Opcodes.size(); > + > + assert(numInstructions && "Filter created with no instructions"); > + > + // No further filtering is necessary. > + if (numInstructions == 1) > + return true; > + > + // Heuristics. See also doFilter()'s "Heuristics" comment when num of > + // instructions is 3. > + if (AllowMixed && !Greedy) { > + assert(numInstructions == 3); > + > + for (unsigned i = 0; i < Opcodes.size(); ++i) { > + std::vector StartBits; > + std::vector EndBits; > + std::vector FieldVals; > + insn_t Insn; > + > + insnWithID(Insn, Opcodes[i]); > + > + // Look for islands of undecoded bits of any instruction. > + if (getIslands(StartBits, EndBits, FieldVals, Insn) > 0) { > + // Found an instruction with island(s). Now just assign a filter. > + runSingleFilter(*this, StartBits[0], EndBits[0] - StartBits[0] + 1, > + true); > + return true; > + } > + } > + } > + > + unsigned bitIndex, insnIndex; > + > + // We maintain tBitWidth copies of the bitAttrs automaton. > + // The automaton consumes the corresponding bit from each > + // instruction. > + // > + // Input symbols: 0, 1, and _ (unset). > + // States: NONE, FILTERED, ALL_SET, ALL_UNSET, and MIXED. > + // Initial state: NONE. > + // > + // (NONE) ------- [01] -> (ALL_SET) > + // (NONE) ------- _ ----> (ALL_UNSET) > + // (ALL_SET) ---- [01] -> (ALL_SET) > + // (ALL_SET) ---- _ ----> (MIXED) > + // (ALL_UNSET) -- [01] -> (MIXED) > + // (ALL_UNSET) -- _ ----> (ALL_UNSET) > + // (MIXED) ------ . ----> (MIXED) > + // (FILTERED)---- . ----> (FILTERED) > + > + bitAttr_t bitAttrs[tBitWidth]; > + > + // FILTERED bit positions provide no entropy and are not worthy of pursuing. > + // Filter::recurse() set either BIT_TRUE or BIT_FALSE for each position. > + for (bitIndex = 0; bitIndex < tBitWidth; ++bitIndex) > + if (FilterBitValues[bitIndex] == BIT_TRUE || > + FilterBitValues[bitIndex] == BIT_FALSE) > + bitAttrs[bitIndex] = ATTR_FILTERED; > + else > + bitAttrs[bitIndex] = ATTR_NONE; > + > + for (insnIndex = 0; insnIndex < numInstructions; ++insnIndex) { > + insn_t insn; > + > + insnWithID(insn, Opcodes[insnIndex]); > + > + for (bitIndex = 0; bitIndex < tBitWidth; ++bitIndex) { > + switch (bitAttrs[bitIndex]) { > + case ATTR_NONE: > + if (insn[bitIndex] == BIT_UNSET) > + bitAttrs[bitIndex] = ATTR_ALL_UNSET; > + else > + bitAttrs[bitIndex] = ATTR_ALL_SET; > + break; > + case ATTR_ALL_SET: > + if (insn[bitIndex] == BIT_UNSET) > + bitAttrs[bitIndex] = ATTR_MIXED; > + break; > + case ATTR_ALL_UNSET: > + if (insn[bitIndex] != BIT_UNSET) > + bitAttrs[bitIndex] = ATTR_MIXED; > + break; > + case ATTR_MIXED: > + case ATTR_FILTERED: > + break; > + } > + } > + } > + > + // The regionAttr automaton consumes the bitAttrs automatons' state, > + // lowest-to-highest. > + // > + // Input symbols: F(iltered), (all_)S(et), (all_)U(nset), M(ixed) > + // States: NONE, ALL_SET, MIXED > + // Initial state: NONE > + // > + // (NONE) ----- F --> (NONE) > + // (NONE) ----- S --> (ALL_SET) ; and set region start > + // (NONE) ----- U --> (NONE) > + // (NONE) ----- M --> (MIXED) ; and set region start > + // (ALL_SET) -- F --> (NONE) ; and report an ALL_SET region > + // (ALL_SET) -- S --> (ALL_SET) > + // (ALL_SET) -- U --> (NONE) ; and report an ALL_SET region > + // (ALL_SET) -- M --> (MIXED) ; and report an ALL_SET region > + // (MIXED) ---- F --> (NONE) ; and report a MIXED region > + // (MIXED) ---- S --> (ALL_SET) ; and report a MIXED region > + // (MIXED) ---- U --> (NONE) ; and report a MIXED region > + // (MIXED) ---- M --> (MIXED) > + > + bitAttr_t regionAttr = ATTR_NONE; > + unsigned startBit = 0; > + > + for (bitIndex = 0; bitIndex < tBitWidth; bitIndex++) { > + bitAttr_t bitAttr = bitAttrs[bitIndex]; > + > + assert(bitAttr != ATTR_NONE && "Bit without attributes"); > + > +#define SET_START \ > + startBit = bitIndex; > + > +#define REPORT_REGION \ > + if (regionAttr == ATTR_MIXED && AllowMixed) \ > + Filters.push_back(Filter(*this, startBit, bitIndex - startBit, true)); \ > + else if (regionAttr == ATTR_ALL_SET && !AllowMixed) \ > + Filters.push_back(Filter(*this, startBit, bitIndex - startBit, false)); > + > + switch (regionAttr) { > + case ATTR_NONE: > + switch (bitAttr) { > + case ATTR_FILTERED: > + break; > + case ATTR_ALL_SET: > + SET_START > + regionAttr = ATTR_ALL_SET; > + break; > + case ATTR_ALL_UNSET: > + break; > + case ATTR_MIXED: > + SET_START > + regionAttr = ATTR_MIXED; > + break; > + default: > + assert(0 && "Unexpected bitAttr!"); > + } > + break; > + case ATTR_ALL_SET: > + switch (bitAttr) { > + case ATTR_FILTERED: > + REPORT_REGION > + regionAttr = ATTR_NONE; > + break; > + case ATTR_ALL_SET: > + break; > + case ATTR_ALL_UNSET: > + REPORT_REGION > + regionAttr = ATTR_NONE; > + break; > + case ATTR_MIXED: > + REPORT_REGION > + SET_START > + regionAttr = ATTR_MIXED; > + break; > + default: > + assert(0 && "Unexpected bitAttr!"); > + } > + break; > + case ATTR_MIXED: > + switch (bitAttr) { > + case ATTR_FILTERED: > + REPORT_REGION > + SET_START > + regionAttr = ATTR_NONE; > + break; > + case ATTR_ALL_SET: > + REPORT_REGION > + SET_START > + regionAttr = ATTR_ALL_SET; > + break; > + case ATTR_ALL_UNSET: > + REPORT_REGION > + regionAttr = ATTR_NONE; > + break; > + case ATTR_MIXED: > + break; > + default: > + assert(0 && "Unexpected bitAttr!"); > + } > + break; > + case ATTR_ALL_UNSET: > + assert(0 && "regionAttr state machine has no ATTR_UNSET state"); > + case ATTR_FILTERED: > + assert(0 && "regionAttr state machine has no ATTR_FILTERED state"); > + } > + } > + > + // At the end, if we're still in ALL_SET or MIXED states, report a region > + > + switch (regionAttr) { > + case ATTR_NONE: > + break; > + case ATTR_FILTERED: > + break; > + case ATTR_ALL_SET: > + REPORT_REGION > + break; > + case ATTR_ALL_UNSET: > + break; > + case ATTR_MIXED: > + REPORT_REGION > + break; > + } > + > +#undef SET_START > +#undef REPORT_REGION > + > + // We have finished with the filter processings. Now it's time to choose > + // the best performing filter. > + > + BestIndex = 0; > + bool AllUseless = true; > + unsigned BestScore = 0; > + > + for (unsigned i = 0, e = Filters.size(); i != e; ++i) { > + unsigned Usefulness = Filters[i].usefulness(); > + > + if (Usefulness) > + AllUseless = false; > + > + if (Usefulness > BestScore) { > + BestIndex = i; > + BestScore = Usefulness; > + } > + } > + > + if (!AllUseless) { > + bestFilter().recurse(); > + } > + > + return !AllUseless; > + } // end of filterProcessor(bool) > + > + // Decides on the best configuration of filter(s) to use in order to decode > + // the instructions. A conflict of instructions may occur, in which case we > + // dump the conflict set to the standard error. > + void doFilter() { > + unsigned Num = Opcodes.size(); > + assert(Num && "FilterChooser created with no instructions"); > + > + // Heuristics: Use Inst{31-28} as the top level filter for ARM ISA. > + if (TargetName == TARGET_ARM && Parent == NULL) { > + runSingleFilter(*this, 28, 4, false); > + return; > + } > + > + if (filterProcessor(false)) > + return; > + > + if (filterProcessor(true)) > + return; > + > + // Heuristics to cope with conflict set {t2CMPrs, t2SUBSrr, t2SUBSrs} where > + // no single instruction for the maximum ATTR_MIXED region Inst{14-4} has a > + // well-known encoding pattern. In such case, we backtrack and scan for the > + // the very first consecutive ATTR_ALL_SET region and assign a filter to it. > + if (Num == 3 && filterProcessor(true, false)) > + return; > + > + // If we come to here, the instruction decoding has failed. > + // Print out the instructions in the conflict set... > + > + BestIndex = -1; > + > + DEBUG({ > + errs() << "Conflict:\n"; > + > + dumpStack(errs(), "\t\t"); > + > + for (unsigned i = 0; i < Num; i++) { > + const std::string &Name = nameWithID(Opcodes[i]); > + > + errs() << '\t' << Name << " "; > + dumpBits(errs(), > + getBitsField(*AllInstructions[Opcodes[i]]->TheDef, "Inst")); > + errs() << '\n'; > + } > + }); > + } > + > + // Emits code to decode our share of instructions. Returns true if the > + // emitted code causes a return, which occurs if we know how to decode > + // the instruction at this level or the instruction is not decodeable. > + bool emit(raw_ostream &o, Indenter &i) { > + if (Opcodes.size() == 1) { > + // There is only one instruction in the set, which is great! > + // Call emitSingletonDecoder() to see whether there are any remaining > + // encodings bits. > + return emitSingletonDecoder(o, i, Opcodes[0]); > + > + } else if (BestIndex == -1) { > + if (TargetName == TARGET_ARM && Opcodes.size() == 2) { > + // Resolve the known conflict sets: > + // > + // 1. source registers are identical => VMOVDneon; otherwise => VORRd > + // 2. source registers are identical => VMOVQ; otherwise => VORRq > + // 3. LDR, LDRcp => return LDR for now. > + // FIXME: How can we distinguish between LDR and LDRcp? Do we need to? > + // 4. VLD[234]LN*a/VST[234]LN*a vs. VLD[234]LN*b/VST[234]LN*b conflicts > + // are resolved returning the 'a' versions of the instructions. Note > + // that the difference between a/b is that the former is for double- > + // spaced even registers while the latter is for double-spaced odd > + // registers. This is for codegen instruction selection purpose. > + // For disassembly, it does not matter. > + const std::string &name1 = nameWithID(Opcodes[0]); > + const std::string &name2 = nameWithID(Opcodes[1]); > + if ((name1 == "VMOVDneon" && name2 == "VORRd") || > + (name1 == "VMOVQ" && name2 == "VORRq")) { > + // Inserting the opening curly brace for this case block. > + i.pop(); > + o.indent(i) << "{\n"; > + i.push(); > + > + o.indent(i) << "field_t N = fieldFromInstruction(insn, 7, 1), " > + << "M = fieldFromInstruction(insn, 5, 1);\n"; > + o.indent(i) << "field_t Vn = fieldFromInstruction(insn, 16, 4), " > + << "Vm = fieldFromInstruction(insn, 0, 4);\n"; > + o.indent(i) << "return (N == M && Vn == Vm) ? " > + << Opcodes[0] << " /* " << name1 << " */ : " > + << Opcodes[1] << " /* " << name2 << " */ ;\n"; > + > + // Inserting the closing curly brace for this case block. > + i.pop(); > + o.indent(i) << "}\n"; > + i.push(); > + > + return true; > + } > + if (name1 == "LDR" && name2 == "LDRcp") { > + o.indent(i) << "return " << Opcodes[0] > + << "; // Returning LDR for {LDR, LDRcp}\n"; > + return true; > + } > + if (sameStringExceptEndingChar(name1, name2, 'a', 'b')) { > + o.indent(i) << "return " << Opcodes[0] << "; // Returning " << name1 > + << " for {" << name1 << ", " << name2 << "}\n"; > + return true; > + } > + > + // Otherwise, it does not belong to the known conflict sets. > + } > + // We don't know how to decode these instructions! Dump the conflict set! > + o.indent(i) << "return 0;" << " // Conflict set: "; > + for (int i = 0, N = Opcodes.size(); i < N; ++i) { > + o << nameWithID(Opcodes[i]); > + if (i < (N - 1)) > + o << ", "; > + else > + o << '\n'; > + } > + return true; > + } else { > + // Choose the best filter to do the decodings! > + Filter &Best = bestFilter(); > + if (Best.getNumFiltered() == 1) > + emitSingletonDecoder(o, i, Best); > + else > + bestFilter().emit(o, i); > + return false; > + } > + } > +}; > + > +/////////////// > +// Backend // > +/////////////// > + > +class RISCDisassemblerEmitter::RISCDEBackend { > +public: > + RISCDEBackend(RISCDisassemblerEmitter &frontend) : > + NumberedInstructions(), > + Opcodes(), > + Frontend(frontend), > + Target(), > + AFC(NULL) > + { > + populateInstructions(); > + > + if (Target.getName() == "ARM") { > + TargetName = TARGET_ARM; > + } else { > + errs() << "Target name " << Target.getName() << " not recognized\n"; > + assert(0 && "Unknown target"); > + } > + } > + > + ~RISCDEBackend() { > + if (AFC) { > + delete AFC; > + AFC = NULL; > + } > + } > + > + void getInstructionsByEnumValue(std::vector > + &NumberedInstructions) { > + // Dig down to the proper namespace. Code shamelessly stolen from > + // InstrEnumEmitter.cpp > + std::string Namespace; > + CodeGenTarget::inst_iterator II, E; > + > + for (II = Target.inst_begin(), E = Target.inst_end(); II != E; ++II) > + if (II->second.Namespace != "TargetInstrInfo") { > + Namespace = II->second.Namespace; > + break; > + } > + > + assert(!Namespace.empty() && "No instructions defined."); > + > + Target.getInstructionsByEnumValue(NumberedInstructions); > + } > + > + bool populateInstruction(const CodeGenInstruction &CGI, TARGET_NAME_t TN) { > + const Record &Def = *CGI.TheDef; > + const std::string &Name = Def.getName(); > + uint8_t Form = getByteField(Def, "Form"); > + BitsInit &Bits = getBitsField(Def, "Inst"); > + > + if (TN == TARGET_ARM) { > + // FIXME: what about Int_MemBarrierV6 and Int_SyncBarrierV6? > + if ((Name != "Int_MemBarrierV7" && Name != "Int_SyncBarrierV7") && > + Form == ARM_FORMAT_PSEUDO) > + return false; > + if (thumbInstruction(Form)) > + return false; > + if (Name.find("CMPz") != std::string::npos /* || > + Name.find("CMNz") != std::string::npos */) > + return false; > + > + // Ignore pseudo instructions. > + if (Name == "BXr9" || Name == "BMOVPCRX" || Name == "BMOVPCRXr9") > + return false; > + > + // VLDRQ/VSTRQ can be hanlded with the more generic VLDMD/VSTMD. > + if (Name == "VLDRQ" || Name == "VSTRQ") > + return false; > + > + // > + // The following special cases are for conflict resolutions. > + // > + > + // RSCSri and RSCSrs set the 's' bit, but are not predicated. We are > + // better off using the generic RSCri and RSCrs instructions. > + if (Name == "RSCSri" || Name == "RSCSrs") return false; > + > + // MOVCCr, MOVCCs, MOVCCi, FCYPScc, FCYPDcc, FNEGScc, and FNEGDcc are used > + // in the compiler to implement conditional moves. We can ignore them in > + // favor of their more generic versions of instructions. > + // See also SDNode *ARMDAGToDAGISel::Select(SDValue Op). > + if (Name == "MOVCCr" || Name == "MOVCCs" || Name == "MOVCCi" || > + Name == "FCPYScc" || Name == "FCPYDcc" || > + Name == "FNEGScc" || Name == "FNEGDcc") > + return false; > + > + // Ditto for VMOVDcc, VMOVScc, VNEGDcc, and VNEGScc. > + if (Name == "VMOVDcc" || Name == "VMOVScc" || Name == "VNEGDcc" || > + Name == "VNEGScc") > + return false; > + > + // Ignore the *_sfp instructions when decoding. They are used by the > + // compiler to implement scalar floating point operations using vector > + // operations in order to work around some performance issues. > + if (Name.find("_sfp") != std::string::npos) return false; > + > + // LLVM added LDM/STM_UPD which conflicts with LDM/STM. > + // Ditto for VLDMS_UPD, VLDMD_UPD, VSTMS_UPD, VSTMD_UPD. > + if (Name == "LDM_UPD" || Name == "STM_UPD" || Name == "VLDMS_UPD" || > + Name == "VLDMD_UPD" || Name == "VSTMS_UPD" || Name == "VSTMD_UPD") > + return false; > + > + // LDM_RET is a special case of LDM (Load Multiple) where the registers > + // loaded include the PC, causing a branch to a loaded address. Ignore > + // the LDM_RET instruction when decoding. > + if (Name == "LDM_RET") return false; > + > + // Bcc is in a more generic form than B. Ignore B when decoding. > + if (Name == "B") return false; > + > + // Ignore the non-Darwin BL instructions and the TPsoft (TLS) instruction. > + if (Name == "BL" || Name == "BL_pred" || Name == "BLX" || Name == "BX" || > + Name == "TPsoft") > + return false; > + > + // Ignore VDUPf[d|q] instructions known to conflict with VDUP32[d-q] for > + // decoding. The instruction duplicates an element from an ARM core > + // register into every element of the destination vector. There is no > + // distinction between data types. > + if (Name == "VDUPfd" || Name == "VDUPfq") return false; > + > + // A8-598: VEXT > + // Vector Extract extracts elements from the bottom end of the second > + // operand vector and the top end of the first, concatenates them and > + // places the result in the destination vector. The elements of the > + // vectors are treated as being 8-bit bitfields. There is no distinction > + // between data types. The size of the operation can be specified in > + // assembler as vext.size. If the value is 16, 32, or 64, the syntax is > + // a pseudo-instruction for a VEXT instruction specifying the equivalent > + // number of bytes. > + // > + // Variants VEXTd16, VEXTd32, VEXTd8, and VEXTdf are reduced to VEXTd8; > + // variants VEXTq16, VEXTq32, VEXTq8, and VEXTqf are reduced to VEXTq8. > + if (Name == "VEXTd16" || Name == "VEXTd32" || Name == "VEXTdf" || > + Name == "VEXTq16" || Name == "VEXTq32" || Name == "VEXTqf") > + return false; > + > + // Vector Reverse is similar to Vector Extract. There is no distinction > + // between data types, other than size. > + // > + // VREV64df is equivalent to VREV64d32. > + // VREV64qf is equivalent to VREV64q32. > + if (Name == "VREV64df" || Name == "VREV64qf") return false; > + > + // VDUPLNfd is equivalent to VDUPLN32d; VDUPfdf is specialized VDUPLN32d. > + // VDUPLNfq is equivalent to VDUPLN32q; VDUPfqf is specialized VDUPLN32q. > + // VLD1df is equivalent to VLD1d32. > + // VLD1qf is equivalent to VLD1q32. > + // VLD2d64 is equivalent to VLD1q64. > + // VST1df is equivalent to VST1d32. > + // VST1qf is equivalent to VST1q32. > + // VST2d64 is equivalent to VST1q64. > + if (Name == "VDUPLNfd" || Name == "VDUPfdf" || > + Name == "VDUPLNfq" || Name == "VDUPfqf" || > + Name == "VLD1df" || Name == "VLD1qf" || Name == "VLD2d64" || > + Name == "VST1df" || Name == "VST1qf" || Name == "VST2d64") > + return false; > + } else if (TN == TARGET_THUMB) { > + if (!thumbInstruction(Form)) > + return false; > + > + // Ignore pseudo instructions. > + if (Name == "tInt_eh_sjlj_setjmp" || Name == "t2Int_eh_sjlj_setjmp" || > + Name == "t2MOVi32imm" || Name == "tBX" || Name == "tBXr9") > + return false; > + > + // LLVM added tLDM_UPD which conflicts with tLDM. > + if (Name == "tLDM_UPD") > + return false; > + > + // On Darwin R9 is call-clobbered. Ignore the non-Darwin counterparts. > + if (Name == "tBL" || Name == "tBLXi" || Name == "tBLXr") > + return false; > + > + // Ignore the TPsoft (TLS) instructions, which conflict with tBLr9. > + if (Name == "tTPsoft" || Name == "t2TPsoft") > + return false; > + > + // Ignore tLEApcrel and tLEApcrelJT, prefer tADDrPCi. > + if (Name == "tLEApcrel" || Name == "tLEApcrelJT") > + return false; > + > + // Ignore t2LEApcrel, prefer the generic t2ADD* for disassembly printing. > + if (Name == "t2LEApcrel") > + return false; > + > + // Ignore tADDrSP, tADDspr, and tPICADD, prefer the generic tADDhirr. > + // Ignore t2SUBrSPs, prefer the t2SUB[S]r[r|s]. > + // Ignore t2ADDrSPs, prefer the t2ADD[S]r[r|s]. > + if (Name == "tADDrSP" || Name == "tADDspr" || Name == "tPICADD" || > + Name == "t2SUBrSPs" || Name == "t2ADDrSPs") > + return false; > + > + // Ignore t2LDRDpci, prefer the generic t2LDRDi8, t2LDRD_PRE, t2LDRD_POST. > + if (Name == "t2LDRDpci") > + return false; > + > + // Ignore t2TBB, t2TBH and prefer the generic t2TBBgen, t2TBHgen. > + if (Name == "t2TBB" || Name == "t2TBH") > + return false; > + > + // Resolve conflicts: > + // > + // tBfar conflicts with tBLr9 > + // tCMNz conflicts with tCMN (with assembly format strings being equal) > + // tPOP_RET/t2LDM_RET conflict with tPOP/t2LDM (ditto) > + // tMOVCCi conflicts with tMOVi8 > + // tMOVCCr conflicts with tMOVgpr2gpr > + // tBR_JTr conflicts with tBRIND > + // tSpill conflicts with tSTRspi > + // tLDRcp conflicts with tLDRspi > + // tRestore conflicts with tLDRspi > + // t2LEApcrelJT conflicts with t2LEApcrel > + // t2ADDrSPi/t2SUBrSPi have more generic couterparts > + if (Name == "tBfar" || > + /* Name == "tCMNz" || */ Name == "tCMPzi8" || Name == "tCMPzr" || > + Name == "tCMPzhir" || /* Name == "t2CMNzrr" || Name == "t2CMNzrs" || > + Name == "t2CMNzri" || */ Name == "t2CMPzrr" || Name == "t2CMPzrs" || > + Name == "t2CMPzri" || Name == "tPOP_RET" || Name == "t2LDM_RET" || > + Name == "tMOVCCi" || Name == "tMOVCCr" || Name == "tBR_JTr" || > + Name == "tSpill" || Name == "tLDRcp" || Name == "tRestore" || > + Name == "t2LEApcrelJT" || Name == "t2ADDrSPi" || Name == "t2SUBrSPi") > + return false; > + } > + > + // Dumps the instruction encoding format. > + switch (TargetName) { > + case TARGET_ARM: > + case TARGET_THUMB: > + DEBUG(errs() << Name << " " << stringForARMFormat((ARMFormat)Form)); > + break; > + } > + > + DEBUG({ > + errs() << " "; > + > + // Dumps the instruction encoding bits. > + dumpBits(errs(), Bits); > + > + errs() << '\n'; > + > + // Dumps the list of operand info. > + for (unsigned i = 0, e = CGI.OperandList.size(); i != e; ++i) { > + CodeGenInstruction::OperandInfo Info = CGI.OperandList[i]; > + const std::string &OperandName = Info.Name; > + const Record &OperandDef = *Info.Rec; > + > + errs() << "\t" << OperandName << " (" << OperandDef.getName() << ")\n"; > + } > + }); > + > + return true; > + } > + > + void populateInstructions() { > + getInstructionsByEnumValue(NumberedInstructions); > + > + uint16_t numUIDs = NumberedInstructions.size(); > + uint16_t uid; > + > + const char *instClass = NULL; > + > + switch (TargetName) { > + case TARGET_ARM: > + instClass = "InstARM"; > + break; > + default: > + assert(0 && "Unreachable code!"); > + } > + > + for (uid = 0; uid < numUIDs; uid++) { > + // filter out intrinsics > + if (!NumberedInstructions[uid]->TheDef->isSubClassOf(instClass)) > + continue; > + > + if (populateInstruction(*NumberedInstructions[uid], TargetName)) > + Opcodes.push_back(uid); > + } > + > + // Special handling for the ARM chip, which supports two modes of execution. > + // This branch handles the Thumb opcodes. > + if (TargetName == TARGET_ARM) { > + for (uid = 0; uid < numUIDs; uid++) { > + // filter out intrinsics > + if (!NumberedInstructions[uid]->TheDef->isSubClassOf("InstARM") > + && !NumberedInstructions[uid]->TheDef->isSubClassOf("InstThumb")) > + continue; > + > + if (populateInstruction(*NumberedInstructions[uid], TARGET_THUMB)) > + Opcodes2.push_back(uid); > + } > + } > + } > + > + // Emits disassembler code for instruction decoding. This delegates to the > + // FilterChooser instance to do the heavy lifting. > + void emit(raw_ostream &o) { > + Indenter i; > + std::string s; > + raw_string_ostream ro(s); > + > + switch (TargetName) { > + case TARGET_ARM: > + Frontend.EmitSourceFileHeader("ARM Disassembler", ro); > + break; > + default: > + assert(0 && "Unreachable code!"); > + } > + > + ro.flush(); > + o << s; > + > + o.indent(i) << "#include \n"; > + o.indent(i) << "#include \n"; > + o << '\n'; > + o << "namespace llvm {\n\n"; > + > + AbstractFilterChooser::setTargetName(TargetName); > + > + switch (TargetName) { > + case TARGET_ARM: { > + // Emit common utility and ARM ISA decoder. > + AFC = new FilterChooser<32>(NumberedInstructions, Opcodes); > + AFC->emitTop(o, i); > + delete AFC; > + > + // Emit Thumb ISA decoder as well. > + AbstractFilterChooser::setTargetName(TARGET_THUMB); > + AFC = new FilterChooser<32>(NumberedInstructions, Opcodes2); > + AFC->emitBot(o, i); > + break; > + } > + default: > + assert(0 && "Unreachable code!"); > + } > + > + o << "\n} // End llvm namespace \n"; > + } > + > +protected: > + std::vector NumberedInstructions; > + std::vector Opcodes; > + // Special case for the ARM chip, which supports ARM and Thumb ISAs. > + // Opcodes2 will be populated with the Thumb opcodes. > + std::vector Opcodes2; > + RISCDisassemblerEmitter &Frontend; > + CodeGenTarget Target; > + AbstractFilterChooser *AFC; > + > + TARGET_NAME_t TargetName; > +}; > + > +///////////////////////// > +// Backend interface // > +///////////////////////// > + > +void RISCDisassemblerEmitter::initBackend() > +{ > + Backend = new RISCDEBackend(*this); > +} > + > +void RISCDisassemblerEmitter::run(raw_ostream &o) > +{ > + Backend->emit(o); > +} > + > +void RISCDisassemblerEmitter::shutdownBackend() > +{ > + delete Backend; > + Backend = NULL; > +} > > Added: llvm/trunk/utils/TableGen/RISCDisassemblerEmitter.h > URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/utils/TableGen/RISCDisassemblerEmitter.h?rev=98637&view=auto > ============================================================================== > --- llvm/trunk/utils/TableGen/RISCDisassemblerEmitter.h (added) > +++ llvm/trunk/utils/TableGen/RISCDisassemblerEmitter.h Tue Mar 16 11:36:54 2010 > @@ -0,0 +1,48 @@ > +//===- RISCDisassemblerEmitter.h - Disassembler Generator -------*- C++ -*-===// > +// > +// The LLVM Compiler Infrastructure > +// > +// This file is distributed under the University of Illinois Open Source > +// License. See LICENSE.TXT for details. > +// > +//===----------------------------------------------------------------------===// > +// > +// FIXME: document > +// > +//===----------------------------------------------------------------------===// > + > +#ifndef RISCDISASSEMBLEREMITTER_H > +#define RISCDISASSEMBLEREMITTER_H > + > +#include "TableGenBackend.h" > + > +#include > + > +namespace llvm { > + > +class RISCDisassemblerEmitter : public TableGenBackend { > + RecordKeeper &Records; > +public: > + RISCDisassemblerEmitter(RecordKeeper &R) : Records(R) { > + initBackend(); > + } > + > + ~RISCDisassemblerEmitter() { > + shutdownBackend(); > + } > + > + // run - Output the code emitter > + void run(raw_ostream &o); > + > +private: > + class RISCDEBackend; > + > + RISCDEBackend *Backend; > + > + void initBackend(); > + void shutdownBackend(); > +}; > + > +} // end llvm namespace > + > +#endif > > Modified: llvm/trunk/utils/TableGen/TableGen.cpp > URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/utils/TableGen/TableGen.cpp?rev=98637&r1=98636&r2=98637&view=diff > ============================================================================== > --- llvm/trunk/utils/TableGen/TableGen.cpp (original) > +++ llvm/trunk/utils/TableGen/TableGen.cpp Tue Mar 16 11:36:54 2010 > @@ -31,6 +31,7 @@ > #include "OptParserEmitter.h" > #include "Record.h" > #include "RegisterInfoEmitter.h" > +#include "RISCDisassemblerEmitter.h" > #include "SubtargetEmitter.h" > #include "TGParser.h" > #include "llvm/Support/CommandLine.h" > @@ -48,6 +49,7 @@ > GenEmitter, > GenRegisterEnums, GenRegister, GenRegisterHeader, > GenInstrEnums, GenInstrs, GenAsmWriter, GenAsmMatcher, > + GenRISCDisassembler, > GenDisassembler, > GenCallingConv, > GenClangDiagsDefs, > @@ -84,6 +86,9 @@ > "Generate calling convention descriptions"), > clEnumValN(GenAsmWriter, "gen-asm-writer", > "Generate assembly writer"), > + clEnumValN(GenRISCDisassembler, "gen-risc-disassembler", > + "Generate disassembler for fixed instruction" > + " length"), > clEnumValN(GenDisassembler, "gen-disassembler", > "Generate disassembler"), > clEnumValN(GenAsmMatcher, "gen-asm-matcher", > @@ -229,6 +234,9 @@ > case GenAsmWriter: > AsmWriterEmitter(Records).run(*Out); > break; > + case GenRISCDisassembler: > + RISCDisassemblerEmitter(Records).run(*Out); > + break; > case GenAsmMatcher: > AsmMatcherEmitter(Records).run(*Out); > break; > > > _______________________________________________ > llvm-commits mailing list > llvm-commits at cs.uiuc.edu > http://lists.cs.uiuc.edu/mailman/listinfo/llvm-commits From jiahong.chen at me.com Tue Mar 16 11:54:15 2010 From: jiahong.chen at me.com (Johnny Chen) Date: Tue, 16 Mar 2010 09:54:15 -0700 Subject: [llvm-commits] [llvm] r98637 - in /llvm/trunk: ./ lib/Target/ARM/ lib/Target/ARM/AsmPrinter/ lib/Target/ARM/Disassembler/ test/CodeGen/ARM/ test/CodeGen/Thumb2/ utils/TableGen/ In-Reply-To: References: <20100316163655.029872A6C12C@llvm.org> Message-ID: <0E0C9404-929E-4973-A826-17EF235E4974@me.com> Sorry. I meant zeroing the top two bytes of the 16-bit thumb instructions before feeding it to the decoder which expects a 4-byte instruction in this case. On Mar 16, 2010, at 9:51 AM, Johnny Chen wrote: > Fixed length. I treated Thumb/Thumb2 instructions as "fixed" length in this regard, > zeroing the the top two bytes. It is easier for me to generate the decoder function > for Thumb/Thumb2 this way. > > Thanks. > > On Mar 16, 2010, at 9:45 AM, Anton Korobeynikov wrote: > >> Hi, Johny >> >>> Initial ARM/Thumb disassembler check-in. It consists of a tablgen backend >>> (RISCDisassemblerEmitter) which emits the decoder functions for ARM and Thumb, >>> and the disassembler core which invokes the decoder function and builds up the >>> MCInst based on the decoded Opcode. >> Quick q: here RISC means "completely fixed length"? Or, say, the >> instructions might be 16/32/24 bits length (contain 1/2 optional >> address fields)? >> >> -- >> With best regards, Anton Korobeynikov >> Faculty of Mathematics and Mechanics, Saint Petersburg State University > From benny.kra at googlemail.com Tue Mar 16 12:25:42 2010 From: benny.kra at googlemail.com (Benjamin Kramer) Date: Tue, 16 Mar 2010 18:25:42 +0100 Subject: [llvm-commits] [llvm] r98637 - in /llvm/trunk: ./ lib/Target/ARM/ lib/Target/ARM/AsmPrinter/ lib/Target/ARM/Disassembler/ test/CodeGen/ARM/ test/CodeGen/Thumb2/ utils/TableGen/ In-Reply-To: <38B92BD5-443C-47B4-B71D-5AABF1FB1462@apple.com> References: <20100316163655.029872A6C12C@llvm.org> <38B92BD5-443C-47B4-B71D-5AABF1FB1462@apple.com> Message-ID: On 16.03.2010, at 18:01, Bob Wilson wrote: > I've reverted this since it broke the buildbots. I'd like a chance to review this before you re-commit with fixes. Valgrind log ==61801== Conditional jump or move depends on uninitialised value(s) ==61801== at 0x1000E4A2B: llvm::RISCDisassemblerEmitter::RISCDEBackend::populateInstructions() (RISCDisassemblerEmitter.cpp:1635) ==61801== by 0x1000E4C88: llvm::RISCDisassemblerEmitter::RISCDEBackend::RISCDEBackend(llvm::RISCDisassemblerEmitter&) (RISCDisassemblerEmitter.cpp:1382) ==61801== by 0x1000DA4BB: llvm::RISCDisassemblerEmitter::initBackend() (RISCDisassemblerEmitter.cpp:1731) ==61801== by 0x10009FB7C: llvm::RISCDisassemblerEmitter::RISCDisassemblerEmitter(llvm::RecordKeeper&) (RISCDisassemblerEmitter.h:27) ==61801== by 0x10009F7E8: llvm::DisassemblerEmitter::run(llvm::raw_ostream&) (DisassemblerEmitter.cpp:131) ==61801== by 0x10012405E: main (TableGen.cpp:250) ==61801== Uninitialised value was created by a heap allocation ==61801== at 0x1005076DE: operator new(unsigned long) (vg_replace_malloc.c:261) ==61801== by 0x1000DA4AA: llvm::RISCDisassemblerEmitter::initBackend() (RISCDisassemblerEmitter.cpp:1731) ==61801== by 0x10009FB7C: llvm::RISCDisassemblerEmitter::RISCDisassemblerEmitter(llvm::RecordKeeper&) (RISCDisassemblerEmitter.h:27) ==61801== by 0x10009F7E8: llvm::DisassemblerEmitter::run(llvm::raw_ostream&) (DisassemblerEmitter.cpp:131) ==61801== by 0x10012405E: main (TableGen.cpp:250) i.e. populateInstructions was called before TargetName was initialized. From evan.cheng at apple.com Tue Mar 16 12:30:58 2010 From: evan.cheng at apple.com (Evan Cheng) Date: Tue, 16 Mar 2010 10:30:58 -0700 Subject: [llvm-commits] Invalid instcombine transformation In-Reply-To: <1259267143.21630.143.camel@aslstation> References: <1259267143.21630.143.camel@aslstation> Message-ID: <9FF4CE7B-E3DF-4EA2-853F-D4CB5A086800@apple.com> Was this ever fixed? Evan On Nov 26, 2009, at 12:25 PM, Anton Korobeynikov wrote: > Hello, Everyone > > Currently instcombine turns small memcpy's (say, of 1/2/4/8 bytes) > into loads / stores. This seems to be invalid if target does not allow > unaligned access (and even if it allows, it's slower in general). > Consider ARM, there we have: > > 1. Byte loads / stores => no alignment requirement > 2. 2-byte loads / stores => 16 bit alignment requirement > 3. 4-byte loads / stores => 32 bit alignment requirement > > In case of misaligned access in cases 2 and 3 it can be either "fixed" > (if the processor is configured so), or trap (it it doesn't configured > so). > > memcpy allows arbitrary alignment. In such situation, turn of e.g. > memcpy(i8*, i8*, 2, 1) and memcpy(i8*, i8*, 4, 1) into loads / stores > is invalid and thus the transform should be disabled. Same applies to > memset. > > Attached patch allows memcpy => load/store transformation only if memcpy > alignment is not lower than ABI alignment of the load/store type (when > TargetData is available). > > This fixed several bugs in real code running on ARM. > > Ok to commit? > > -- > With best regards, Anton Korobeynikov. > > Faculty of Mathematics & Mechanics, Saint Petersburg State University. > _______________________________________________ > llvm-commits mailing list > llvm-commits at cs.uiuc.edu > http://lists.cs.uiuc.edu/mailman/listinfo/llvm-commits From bob.wilson at apple.com Tue Mar 16 12:44:45 2010 From: bob.wilson at apple.com (Bob Wilson) Date: Tue, 16 Mar 2010 17:44:45 -0000 Subject: [llvm-commits] [llvm] r98642 - in /llvm/trunk/lib/Target/ARM/AsmPrinter: ARMAsmPrinter.cpp ARMInstPrinter.cpp Message-ID: <20100316174446.07BFA2A6C12D@llvm.org> Author: bwilson Date: Tue Mar 16 12:44:45 2010 New Revision: 98642 URL: http://llvm.org/viewvc/llvm-project?rev=98642&view=rev Log: Fix unused variable warnings. Modified: llvm/trunk/lib/Target/ARM/AsmPrinter/ARMAsmPrinter.cpp llvm/trunk/lib/Target/ARM/AsmPrinter/ARMInstPrinter.cpp Modified: llvm/trunk/lib/Target/ARM/AsmPrinter/ARMAsmPrinter.cpp URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Target/ARM/AsmPrinter/ARMAsmPrinter.cpp?rev=98642&r1=98641&r2=98642&view=diff ============================================================================== --- llvm/trunk/lib/Target/ARM/AsmPrinter/ARMAsmPrinter.cpp (original) +++ llvm/trunk/lib/Target/ARM/AsmPrinter/ARMAsmPrinter.cpp Tue Mar 16 12:44:45 2010 @@ -514,7 +514,6 @@ void ARMAsmPrinter::printAddrMode4Operand(const MachineInstr *MI, int Op, const char *Modifier) { - const MachineOperand &MO1 = MI->getOperand(Op); const MachineOperand &MO2 = MI->getOperand(Op+1); ARM_AM::AMSubMode Mode = ARM_AM::getAM4SubMode(MO2.getImm()); if (Modifier && strcmp(Modifier, "submode") == 0) { Modified: llvm/trunk/lib/Target/ARM/AsmPrinter/ARMInstPrinter.cpp URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Target/ARM/AsmPrinter/ARMInstPrinter.cpp?rev=98642&r1=98641&r2=98642&view=diff ============================================================================== --- llvm/trunk/lib/Target/ARM/AsmPrinter/ARMInstPrinter.cpp (original) +++ llvm/trunk/lib/Target/ARM/AsmPrinter/ARMInstPrinter.cpp Tue Mar 16 12:44:45 2010 @@ -222,7 +222,6 @@ void ARMInstPrinter::printAddrMode4Operand(const MCInst *MI, unsigned OpNum, const char *Modifier) { - const MCOperand &MO1 = MI->getOperand(OpNum); const MCOperand &MO2 = MI->getOperand(OpNum+1); ARM_AM::AMSubMode Mode = ARM_AM::getAM4SubMode(MO2.getImm()); if (Modifier && strcmp(Modifier, "submode") == 0) { From johnny.chen at apple.com Tue Mar 16 12:45:52 2010 From: johnny.chen at apple.com (Johnny Chen) Date: Tue, 16 Mar 2010 10:45:52 -0700 Subject: [llvm-commits] [llvm] r98637 - in /llvm/trunk: ./ lib/Target/ARM/ lib/Target/ARM/AsmPrinter/ lib/Target/ARM/Disassembler/ test/CodeGen/ARM/ test/CodeGen/Thumb2/ utils/TableGen/ In-Reply-To: References: <20100316163655.029872A6C12C@llvm.org> <38B92BD5-443C-47B4-B71D-5AABF1FB1462@apple.com> Message-ID: Thanks! On Mar 16, 2010, at 10:25 AM, Benjamin Kramer wrote: > > On 16.03.2010, at 18:01, Bob Wilson wrote: > >> I've reverted this since it broke the buildbots. I'd like a chance to review this before you re-commit with fixes. > > Valgrind log > > ==61801== Conditional jump or move depends on uninitialised value(s) > ==61801== at 0x1000E4A2B: llvm::RISCDisassemblerEmitter::RISCDEBackend::populateInstructions() (RISCDisassemblerEmitter.cpp:1635) > ==61801== by 0x1000E4C88: llvm::RISCDisassemblerEmitter::RISCDEBackend::RISCDEBackend(llvm::RISCDisassemblerEmitter&) (RISCDisassemblerEmitter.cpp:1382) > ==61801== by 0x1000DA4BB: llvm::RISCDisassemblerEmitter::initBackend() (RISCDisassemblerEmitter.cpp:1731) > ==61801== by 0x10009FB7C: llvm::RISCDisassemblerEmitter::RISCDisassemblerEmitter(llvm::RecordKeeper&) (RISCDisassemblerEmitter.h:27) > ==61801== by 0x10009F7E8: llvm::DisassemblerEmitter::run(llvm::raw_ostream&) (DisassemblerEmitter.cpp:131) > ==61801== by 0x10012405E: main (TableGen.cpp:250) > ==61801== Uninitialised value was created by a heap allocation > ==61801== at 0x1005076DE: operator new(unsigned long) (vg_replace_malloc.c:261) > ==61801== by 0x1000DA4AA: llvm::RISCDisassemblerEmitter::initBackend() (RISCDisassemblerEmitter.cpp:1731) > ==61801== by 0x10009FB7C: llvm::RISCDisassemblerEmitter::RISCDisassemblerEmitter(llvm::RecordKeeper&) (RISCDisassemblerEmitter.h:27) > ==61801== by 0x10009F7E8: llvm::DisassemblerEmitter::run(llvm::raw_ostream&) (DisassemblerEmitter.cpp:131) > ==61801== by 0x10012405E: main (TableGen.cpp:250) > > i.e. populateInstructions was called before TargetName was initialized. From bob.wilson at apple.com Tue Mar 16 12:46:45 2010 From: bob.wilson at apple.com (Bob Wilson) Date: Tue, 16 Mar 2010 17:46:45 -0000 Subject: [llvm-commits] [llvm] r98643 - in /llvm/trunk/lib/Target/ARM: ARMAddressingModes.h ARMCodeEmitter.cpp ARMInstrInfo.td ARMInstrThumb.td ARMInstrThumb2.td ARMLoadStoreOptimizer.cpp AsmPrinter/ARMAsmPrinter.cpp AsmPrinter/ARMInstPrinter.cpp Message-ID: <20100316174645.955F32A6C12C@llvm.org> Author: bwilson Date: Tue Mar 16 12:46:45 2010 New Revision: 98643 URL: http://llvm.org/viewvc/llvm-project?rev=98643&view=rev Log: Remove the writeback flag from ARM's address mode 4. Now that we have separate instructions for ld/st with writeback, the flag is completely redundant. Modified: llvm/trunk/lib/Target/ARM/ARMAddressingModes.h llvm/trunk/lib/Target/ARM/ARMCodeEmitter.cpp llvm/trunk/lib/Target/ARM/ARMInstrInfo.td llvm/trunk/lib/Target/ARM/ARMInstrThumb.td llvm/trunk/lib/Target/ARM/ARMInstrThumb2.td llvm/trunk/lib/Target/ARM/ARMLoadStoreOptimizer.cpp llvm/trunk/lib/Target/ARM/AsmPrinter/ARMAsmPrinter.cpp llvm/trunk/lib/Target/ARM/AsmPrinter/ARMInstPrinter.cpp Modified: llvm/trunk/lib/Target/ARM/ARMAddressingModes.h URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Target/ARM/ARMAddressingModes.h?rev=98643&r1=98642&r2=98643&view=diff ============================================================================== --- llvm/trunk/lib/Target/ARM/ARMAddressingModes.h (original) +++ llvm/trunk/lib/Target/ARM/ARMAddressingModes.h Tue Mar 16 12:46:45 2010 @@ -463,20 +463,13 @@ // IB - Increment before // DA - Decrement after // DB - Decrement before - // - // If the 4th bit (writeback)is set, then the base register is updated after - // the memory transfer. static inline AMSubMode getAM4SubMode(unsigned Mode) { return (AMSubMode)(Mode & 0x7); } - static inline unsigned getAM4ModeImm(AMSubMode SubMode, bool WB = false) { - return (int)SubMode | ((int)WB << 3); - } - - static inline bool getAM4WBFlag(unsigned Mode) { - return (Mode >> 3) & 1; + static inline unsigned getAM4ModeImm(AMSubMode SubMode) { + return (int)SubMode; } //===--------------------------------------------------------------------===// Modified: llvm/trunk/lib/Target/ARM/ARMCodeEmitter.cpp URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Target/ARM/ARMCodeEmitter.cpp?rev=98643&r1=98642&r2=98643&view=diff ============================================================================== --- llvm/trunk/lib/Target/ARM/ARMCodeEmitter.cpp (original) +++ llvm/trunk/lib/Target/ARM/ARMCodeEmitter.cpp Tue Mar 16 12:46:45 2010 @@ -950,7 +950,7 @@ Binary |= getAddrModeUPBits(ARM_AM::getAM4SubMode(MO.getImm())); // Set bit W(21) - if (ARM_AM::getAM4WBFlag(MO.getImm())) + if (IsUpdating) Binary |= 0x1 << ARMII::W_BitShift; // Set registers Modified: llvm/trunk/lib/Target/ARM/ARMInstrInfo.td URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Target/ARM/ARMInstrInfo.td?rev=98643&r1=98642&r2=98643&view=diff ============================================================================== --- llvm/trunk/lib/Target/ARM/ARMInstrInfo.td (original) +++ llvm/trunk/lib/Target/ARM/ARMInstrInfo.td Tue Mar 16 12:46:45 2010 @@ -909,7 +909,7 @@ def LDM_RET : AXI4ld<(outs GPR:$wb), (ins addrmode4:$addr, pred:$p, reglist:$dsts, variable_ops), IndexModeUpd, LdStMulFrm, IIC_Br, - "ldm${addr:submode}${p}\t$addr, $dsts", + "ldm${addr:submode}${p}\t$addr!, $dsts", "$addr.addr = $wb", []>; // On non-Darwin platforms R9 is callee-saved. @@ -1354,7 +1354,7 @@ def LDM_UPD : AXI4ld<(outs GPR:$wb), (ins addrmode4:$addr, pred:$p, reglist:$dsts, variable_ops), IndexModeUpd, LdStMulFrm, IIC_iLoadm, - "ldm${addr:submode}${p}\t$addr, $dsts", + "ldm${addr:submode}${p}\t$addr!, $dsts", "$addr.addr = $wb", []>; } // mayLoad, hasExtraDefRegAllocReq @@ -1367,7 +1367,7 @@ def STM_UPD : AXI4st<(outs GPR:$wb), (ins addrmode4:$addr, pred:$p, reglist:$srcs, variable_ops), IndexModeUpd, LdStMulFrm, IIC_iStorem, - "stm${addr:submode}${p}\t$addr, $srcs", + "stm${addr:submode}${p}\t$addr!, $srcs", "$addr.addr = $wb", []>; } // mayStore, hasExtraSrcRegAllocReq Modified: llvm/trunk/lib/Target/ARM/ARMInstrThumb.td URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Target/ARM/ARMInstrThumb.td?rev=98643&r1=98642&r2=98643&view=diff ============================================================================== --- llvm/trunk/lib/Target/ARM/ARMInstrThumb.td (original) +++ llvm/trunk/lib/Target/ARM/ARMInstrThumb.td Tue Mar 16 12:46:45 2010 @@ -549,7 +549,7 @@ def tLDM_UPD : T1It<(outs tGPR:$wb), (ins addrmode4:$addr, pred:$p, reglist:$dsts, variable_ops), IIC_iLoadm, - "ldm${addr:submode}${p}\t$addr, $dsts", + "ldm${addr:submode}${p}\t$addr!, $dsts", "$addr.addr = $wb", []>, T1Encoding<{1,1,0,0,1,?}>; // A6.2 & A8.6.53 } // mayLoad, hasExtraDefRegAllocReq @@ -558,7 +558,7 @@ def tSTM_UPD : T1It<(outs tGPR:$wb), (ins addrmode4:$addr, pred:$p, reglist:$srcs, variable_ops), IIC_iStorem, - "stm${addr:submode}${p}\t$addr, $srcs", + "stm${addr:submode}${p}\t$addr!, $srcs", "$addr.addr = $wb", []>, T1Encoding<{1,1,0,0,0,?}>; // A6.2 & A8.6.189 Modified: llvm/trunk/lib/Target/ARM/ARMInstrThumb2.td URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Target/ARM/ARMInstrThumb2.td?rev=98643&r1=98642&r2=98643&view=diff ============================================================================== --- llvm/trunk/lib/Target/ARM/ARMInstrThumb2.td (original) +++ llvm/trunk/lib/Target/ARM/ARMInstrThumb2.td Tue Mar 16 12:46:45 2010 @@ -1218,7 +1218,7 @@ def t2LDM_UPD : T2XIt<(outs GPR:$wb), (ins addrmode4:$addr, pred:$p, reglist:$dsts, variable_ops), IIC_iLoadm, - "ldm${addr:submode}${p}${addr:wide}\t$addr, $dsts", + "ldm${addr:submode}${p}${addr:wide}\t$addr!, $dsts", "$addr.addr = $wb", []> { let Inst{31-27} = 0b11101; let Inst{26-25} = 0b00; @@ -1244,7 +1244,7 @@ def t2STM_UPD : T2XIt<(outs GPR:$wb), (ins addrmode4:$addr, pred:$p, reglist:$srcs, variable_ops), IIC_iStorem, - "stm${addr:submode}${p}${addr:wide}\t$addr, $srcs", + "stm${addr:submode}${p}${addr:wide}\t$addr!, $srcs", "$addr.addr = $wb", []> { let Inst{31-27} = 0b11101; let Inst{26-25} = 0b00; Modified: llvm/trunk/lib/Target/ARM/ARMLoadStoreOptimizer.cpp URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Target/ARM/ARMLoadStoreOptimizer.cpp?rev=98643&r1=98642&r2=98643&view=diff ============================================================================== --- llvm/trunk/lib/Target/ARM/ARMLoadStoreOptimizer.cpp (original) +++ llvm/trunk/lib/Target/ARM/ARMLoadStoreOptimizer.cpp Tue Mar 16 12:46:45 2010 @@ -505,7 +505,6 @@ if (MI->getOperand(i).getReg() == Base) return false; } - assert(!ARM_AM::getAM4WBFlag(MI->getOperand(1).getImm())); Mode = ARM_AM::getAM4SubMode(MI->getOperand(1).getImm()); } else { // VLDM{D|S}, VSTM{D|S} addressing mode 5 ops. @@ -573,7 +572,7 @@ .addReg(Base, getKillRegState(BaseKill)); if (isAM4) { // [t2]LDM_UPD, [t2]STM_UPD - MIB.addImm(ARM_AM::getAM4ModeImm(Mode, true)) + MIB.addImm(ARM_AM::getAM4ModeImm(Mode)) .addImm(Pred).addReg(PredReg); } else { // VLDM[SD}_UPD, VSTM[SD]_UPD Modified: llvm/trunk/lib/Target/ARM/AsmPrinter/ARMAsmPrinter.cpp URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Target/ARM/AsmPrinter/ARMAsmPrinter.cpp?rev=98643&r1=98642&r2=98643&view=diff ============================================================================== --- llvm/trunk/lib/Target/ARM/AsmPrinter/ARMAsmPrinter.cpp (original) +++ llvm/trunk/lib/Target/ARM/AsmPrinter/ARMAsmPrinter.cpp Tue Mar 16 12:46:45 2010 @@ -524,8 +524,6 @@ O << ".w"; } else { printOperand(MI, Op); - if (ARM_AM::getAM4WBFlag(MO2.getImm())) - O << "!"; } } Modified: llvm/trunk/lib/Target/ARM/AsmPrinter/ARMInstPrinter.cpp URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Target/ARM/AsmPrinter/ARMInstPrinter.cpp?rev=98643&r1=98642&r2=98643&view=diff ============================================================================== --- llvm/trunk/lib/Target/ARM/AsmPrinter/ARMInstPrinter.cpp (original) +++ llvm/trunk/lib/Target/ARM/AsmPrinter/ARMInstPrinter.cpp Tue Mar 16 12:46:45 2010 @@ -232,8 +232,6 @@ O << ".w"; } else { printOperand(MI, OpNum); - if (ARM_AM::getAM4WBFlag(MO2.getImm())) - O << "!"; } } From clattner at apple.com Tue Mar 16 12:52:14 2010 From: clattner at apple.com (Chris Lattner) Date: Tue, 16 Mar 2010 10:52:14 -0700 Subject: [llvm-commits] [llvm-gcc-4.2] r98626 - /llvm-gcc-4.2/trunk/gcc/llvm-backend.cpp In-Reply-To: <20100316113532.C19AA2A6C12C@llvm.org> References: <20100316113532.C19AA2A6C12C@llvm.org> Message-ID: <1DFD651D-2FC7-46B9-AC95-C72E7AB183D7@apple.com> Hi Duncan, This is not safe, please revert it. I originally tried to do this for llvm-gcc 3 and was defeated by libstdc++. It assumes (and it turns out the c++ standard allows this) that global variables are zero initialized before the constructor for a type is run on it. -Chris On Mar 16, 2010, at 4:35 AM, Duncan Sands wrote: > Author: baldrick > Date: Tue Mar 16 06:35:32 2010 > New Revision: 98626 > > URL: http://llvm.org/viewvc/llvm-project?rev=98626&view=rev > Log: > If a global variable is initialized by a code sequence, then do not zero > initialize it: using 'undef' makes it easier for the optimizers to sink > initialization code into the initializer for the global. It is not clear > if this is always correct, since it relies on the code sequence not somehow > making use of the global being zero initialized. My limited experiments > suggest that everything is fine. This is partial progress towards getting > better code out of the testcase in PR6551. > > Modified: > llvm-gcc-4.2/trunk/gcc/llvm-backend.cpp > > Modified: llvm-gcc-4.2/trunk/gcc/llvm-backend.cpp > URL: http://llvm.org/viewvc/llvm-project/llvm-gcc-4.2/trunk/gcc/llvm-backend.cpp?rev=98626&r1=98625&r2=98626&view=diff > ============================================================================== > --- llvm-gcc-4.2/trunk/gcc/llvm-backend.cpp (original) > +++ llvm-gcc-4.2/trunk/gcc/llvm-backend.cpp Tue Mar 16 06:35:32 2010 > @@ -1320,10 +1320,17 @@ > // Convert the initializer over. > Constant *Init; > if (DECL_INITIAL(decl) == 0 || DECL_INITIAL(decl) == error_mark_node) { > - // This global should be zero initialized. Reconvert the type in case the > + // This global does not have an explicit initializer. This usually means > + // that it should be zero initialized. Reconvert the type in case the > // forward def of the global and the real def differ in type (e.g. declared > // as 'int A[]', and defined as 'int A[100]'). > - Init = Constant::getNullValue(ConvertType(TREE_TYPE(decl))); > + if (TYPE_NEEDS_CONSTRUCTING(TREE_TYPE(decl))) { > + // The global will be initialized by a code sequence - it does not need to > + // be zero initialized. > + Init = UndefValue::get(ConvertType(TREE_TYPE(decl))); > + } else { > + Init = Constant::getNullValue(ConvertType(TREE_TYPE(decl))); > + } > } else { > assert((TREE_CONSTANT(DECL_INITIAL(decl)) || > TREE_CODE(DECL_INITIAL(decl)) == STRING_CST) && > > > _______________________________________________ > llvm-commits mailing list > llvm-commits at cs.uiuc.edu > http://lists.cs.uiuc.edu/mailman/listinfo/llvm-commits From evan.cheng at apple.com Tue Mar 16 13:06:37 2010 From: evan.cheng at apple.com (Evan Cheng) Date: Tue, 16 Mar 2010 11:06:37 -0700 Subject: [llvm-commits] [llvm] r98401 - in /llvm/trunk: include/llvm/Analysis/InlineCost.h lib/Analysis/InlineCost.cpp In-Reply-To: <64F33A81-9779-4FEB-B471-15ECB33EE0DE@2pi.dk> References: <20100313001020.E6B472A6C12C@llvm.org> <64F33A81-9779-4FEB-B471-15ECB33EE0DE@2pi.dk> Message-ID: <9264B87A-2AED-4AB9-92A5-2E1C7A38F5DA@apple.com> Fixed? Evan On Mar 12, 2010, at 4:37 PM, Jakob Stoklund Olesen wrote: >> >> >> @@ -142,7 +142,7 @@ >> /// from the specified block. >> void CodeMetrics::analyzeBasicBlock(const BasicBlock *BB) { >> ++NumBlocks; >> - >> + unsigned NumInstsInThisBB = 0; >> for (BasicBlock::const_iterator II = BB->begin(), E = BB->end(); >> II != E; ++II) { >> if (isa(II)) continue; // PHI nodes don't count. >> @@ -196,6 +196,7 @@ >> } >> >> ++NumInsts; >> + ++NumInstsInThisBB; > > I think you should also include 'NumInsts += InlineConstants::CallPenalty + CS.arg_size();' for consistency. > > /jakob > > > _______________________________________________ > llvm-commits mailing list > llvm-commits at cs.uiuc.edu > http://lists.cs.uiuc.edu/mailman/listinfo/llvm-commits From dpatel at apple.com Tue Mar 16 13:11:00 2010 From: dpatel at apple.com (Devang Patel) Date: Tue, 16 Mar 2010 11:11:00 -0700 Subject: [llvm-commits] [llvm] r98401 - in /llvm/trunk: include/llvm/Analysis/InlineCost.h lib/Analysis/InlineCost.cpp In-Reply-To: <9264B87A-2AED-4AB9-92A5-2E1C7A38F5DA@apple.com> References: <20100313001020.E6B472A6C12C@llvm.org> <64F33A81-9779-4FEB-B471-15ECB33EE0DE@2pi.dk> <9264B87A-2AED-4AB9-92A5-2E1C7A38F5DA@apple.com> Message-ID: On Mar 16, 2010, at 11:06 AM, Evan Cheng wrote: > Fixed? Yes. Instead of maintaining bb specific insn count in parallel, I updated code to use difference in NumInsts count. r98408 - Devang From baldrick at free.fr Tue Mar 16 13:14:00 2010 From: baldrick at free.fr (Duncan Sands) Date: Tue, 16 Mar 2010 18:14:00 -0000 Subject: [llvm-commits] [llvm-gcc-4.2] r98646 - /llvm-gcc-4.2/trunk/gcc/llvm-backend.cpp Message-ID: <20100316181400.27F092A6C12C@llvm.org> Author: baldrick Date: Tue Mar 16 13:13:59 2010 New Revision: 98646 URL: http://llvm.org/viewvc/llvm-project?rev=98646&view=rev Log: Revert commit 98626. Chris says: "I originally tried to do this for llvm-gcc 3 and was defeated by libstdc++. It assumes (and it turns out the c++ standard allows this) that global variables are zero initialized before the constructor for a type is run on it." Modified: llvm-gcc-4.2/trunk/gcc/llvm-backend.cpp Modified: llvm-gcc-4.2/trunk/gcc/llvm-backend.cpp URL: http://llvm.org/viewvc/llvm-project/llvm-gcc-4.2/trunk/gcc/llvm-backend.cpp?rev=98646&r1=98645&r2=98646&view=diff ============================================================================== --- llvm-gcc-4.2/trunk/gcc/llvm-backend.cpp (original) +++ llvm-gcc-4.2/trunk/gcc/llvm-backend.cpp Tue Mar 16 13:13:59 2010 @@ -1320,17 +1320,10 @@ // Convert the initializer over. Constant *Init; if (DECL_INITIAL(decl) == 0 || DECL_INITIAL(decl) == error_mark_node) { - // This global does not have an explicit initializer. This usually means - // that it should be zero initialized. Reconvert the type in case the + // This global should be zero initialized. Reconvert the type in case the // forward def of the global and the real def differ in type (e.g. declared // as 'int A[]', and defined as 'int A[100]'). - if (TYPE_NEEDS_CONSTRUCTING(TREE_TYPE(decl))) { - // The global will be initialized by a code sequence - it does not need to - // be zero initialized. - Init = UndefValue::get(ConvertType(TREE_TYPE(decl))); - } else { - Init = Constant::getNullValue(ConvertType(TREE_TYPE(decl))); - } + Init = Constant::getNullValue(ConvertType(TREE_TYPE(decl))); } else { assert((TREE_CONSTANT(DECL_INITIAL(decl)) || TREE_CODE(DECL_INITIAL(decl)) == STRING_CST) && From baldrick at free.fr Tue Mar 16 13:15:46 2010 From: baldrick at free.fr (Duncan Sands) Date: Tue, 16 Mar 2010 19:15:46 +0100 Subject: [llvm-commits] [llvm-gcc-4.2] r98626 - /llvm-gcc-4.2/trunk/gcc/llvm-backend.cpp In-Reply-To: <1DFD651D-2FC7-46B9-AC95-C72E7AB183D7@apple.com> References: <20100316113532.C19AA2A6C12C@llvm.org> <1DFD651D-2FC7-46B9-AC95-C72E7AB183D7@apple.com> Message-ID: <4B9FCAD2.4060405@free.fr> Hi Chris, > This is not safe, please revert it. reverted in commit 98646. > I originally tried to do this for llvm-gcc 3 and was defeated by libstdc++. It assumes (and it turns out the c++ standard allows this) that global variables are zero initialized before the constructor for a type is run on it. That is so annoying! You could do easily do some nice simplifications if this wasn't the case... Ciao, Duncan. From clattner at apple.com Tue Mar 16 13:18:33 2010 From: clattner at apple.com (Chris Lattner) Date: Tue, 16 Mar 2010 11:18:33 -0700 Subject: [llvm-commits] [llvm-gcc-4.2] r98626 - /llvm-gcc-4.2/trunk/gcc/llvm-backend.cpp In-Reply-To: <4B9FCAD2.4060405@free.fr> References: <20100316113532.C19AA2A6C12C@llvm.org> <1DFD651D-2FC7-46B9-AC95-C72E7AB183D7@apple.com> <4B9FCAD2.4060405@free.fr> Message-ID: <845F2FE3-4DAD-4E9B-9696-1536660633CE@apple.com> On Mar 16, 2010, at 11:15 AM, Duncan Sands wrote: >> I originally tried to do this for llvm-gcc 3 and was defeated by libstdc++. It assumes (and it turns out the c++ standard allows this) that global variables are zero initialized before the constructor for a type is run on it. > > That is so annoying! You could do easily do some nice simplifications if this > wasn't the case... Yeah I know. I assume you noticed the globalopt xforms that build on this. I added those back when I thought that the c++ frontend could take advantage of it, then had to revert the frontend changes. -Chris From anton at korobeynikov.info Tue Mar 16 13:24:11 2010 From: anton at korobeynikov.info (Anton Korobeynikov) Date: Tue, 16 Mar 2010 21:24:11 +0300 Subject: [llvm-commits] Invalid instcombine transformation In-Reply-To: <9FF4CE7B-E3DF-4EA2-853F-D4CB5A086800@apple.com> References: <1259267143.21630.143.camel@aslstation> <9FF4CE7B-E3DF-4EA2-853F-D4CB5A086800@apple.com> Message-ID: Hi, Evan > Was this ever fixed? Yes. The real reason was an allowance of unaligned loads in the backend. The code was modified to allow this only on darwin so far. There was another bug there as well. -- With best regards, Anton Korobeynikov Faculty of Mathematics and Mechanics, Saint Petersburg State University From clattner at apple.com Tue Mar 16 13:27:01 2010 From: clattner at apple.com (Chris Lattner) Date: Tue, 16 Mar 2010 11:27:01 -0700 Subject: [llvm-commits] [llvm] r98023 - /llvm/trunk/lib/CodeGen/SimpleRegisterCoalescing.cpp In-Reply-To: References: <20100309005948.483A02A6C12C@llvm.org> <59424131-A98B-428A-9BE7-75786CE199C4@2pi.dk> Message-ID: On Mar 9, 2010, at 10:15 AM, Jakob Stoklund Olesen wrote: > > On Mar 9, 2010, at 9:41 AM, Jakob Stoklund Olesen wrote: > >> >> On Mar 8, 2010, at 5:37 PM, Jakob Stoklund Olesen wrote: >> >>> >>> On Mar 8, 2010, at 5:23 PM, Evan Cheng wrote: >>> >>>> Is 1000 scientific? :-) >>> >> >> The coalescer timing formed a perfect parabola with t=4.1s at N=2000. This is not a caching effect - the coalescer is quadratic in the number of function calls! > > The attached graph shows the coalescer runtime as a function of the array length in my tiny test function (inlining disabled). The patch kicks in at N=500 and reduces runtime to nothing. Is it possible to fix or improve the N^2 algorithm? -Chris From bob.wilson at apple.com Tue Mar 16 13:38:09 2010 From: bob.wilson at apple.com (Bob Wilson) Date: Tue, 16 Mar 2010 18:38:09 -0000 Subject: [llvm-commits] [llvm] r98648 - in /llvm/trunk/lib/Target/ARM: ARMAddressingModes.h ARMCodeEmitter.cpp ARMInstrVFP.td ARMLoadStoreOptimizer.cpp AsmPrinter/ARMAsmPrinter.cpp AsmPrinter/ARMInstPrinter.cpp Message-ID: <20100316183809.696152A6C12C@llvm.org> Author: bwilson Date: Tue Mar 16 13:38:09 2010 New Revision: 98648 URL: http://llvm.org/viewvc/llvm-project?rev=98648&view=rev Log: Remove redundant writeback flag in ARM addressing mode 5. Modified: llvm/trunk/lib/Target/ARM/ARMAddressingModes.h llvm/trunk/lib/Target/ARM/ARMCodeEmitter.cpp llvm/trunk/lib/Target/ARM/ARMInstrVFP.td llvm/trunk/lib/Target/ARM/ARMLoadStoreOptimizer.cpp llvm/trunk/lib/Target/ARM/AsmPrinter/ARMAsmPrinter.cpp llvm/trunk/lib/Target/ARM/AsmPrinter/ARMInstPrinter.cpp Modified: llvm/trunk/lib/Target/ARM/ARMAddressingModes.h URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Target/ARM/ARMAddressingModes.h?rev=98648&r1=98647&r2=98648&view=diff ============================================================================== --- llvm/trunk/lib/Target/ARM/ARMAddressingModes.h (original) +++ llvm/trunk/lib/Target/ARM/ARMAddressingModes.h Tue Mar 16 13:38:09 2010 @@ -484,9 +484,9 @@ // operation in bit 8 and the immediate in bits 0-7. // // This is also used for FP load/store multiple ops. The second operand - // encodes the writeback mode in bit 8 and the number of registers (or 2 - // times the number of registers for DPR ops) in bits 0-7. In addition, - // bits 9-11 encode one of the following two sub-modes: + // encodes the number of registers (or 2 times the number of registers + // for DPR ops) in bits 0-7. In addition, bits 8-10 encode one of the + // following two sub-modes: // // IA - Increment after // DB - Decrement before @@ -505,17 +505,13 @@ /// getAM5Opc - This function encodes the addrmode5 opc field for VLDM and /// VSTM instructions. - static inline unsigned getAM5Opc(AMSubMode SubMode, bool WB, - unsigned char Offset) { + static inline unsigned getAM5Opc(AMSubMode SubMode, unsigned char Offset) { assert((SubMode == ia || SubMode == db) && "Illegal addressing mode 5 sub-mode!"); - return ((int)SubMode << 9) | ((int)WB << 8) | Offset; + return ((int)SubMode << 8) | Offset; } static inline AMSubMode getAM5SubMode(unsigned AM5Opc) { - return (AMSubMode)((AM5Opc >> 9) & 0x7); - } - static inline bool getAM5WBFlag(unsigned AM5Opc) { - return ((AM5Opc >> 8) & 1); + return (AMSubMode)((AM5Opc >> 8) & 0x7); } //===--------------------------------------------------------------------===// Modified: llvm/trunk/lib/Target/ARM/ARMCodeEmitter.cpp URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Target/ARM/ARMCodeEmitter.cpp?rev=98648&r1=98647&r2=98648&view=diff ============================================================================== --- llvm/trunk/lib/Target/ARM/ARMCodeEmitter.cpp (original) +++ llvm/trunk/lib/Target/ARM/ARMCodeEmitter.cpp Tue Mar 16 13:38:09 2010 @@ -1353,7 +1353,7 @@ Binary |= getAddrModeUPBits(ARM_AM::getAM5SubMode(MO.getImm())); // Set bit W(21) - if (ARM_AM::getAM5WBFlag(MO.getImm())) + if (IsUpdating) Binary |= 0x1 << ARMII::W_BitShift; // First register is encoded in Dd. Modified: llvm/trunk/lib/Target/ARM/ARMInstrVFP.td URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Target/ARM/ARMInstrVFP.td?rev=98648&r1=98647&r2=98648&view=diff ============================================================================== --- llvm/trunk/lib/Target/ARM/ARMInstrVFP.td (original) +++ llvm/trunk/lib/Target/ARM/ARMInstrVFP.td Tue Mar 16 13:38:09 2010 @@ -94,7 +94,7 @@ def VLDMD_UPD : AXDI5<(outs GPR:$wb), (ins addrmode5:$addr, pred:$p, reglist:$dsts, variable_ops), IndexModeUpd, IIC_fpLoadm, - "vldm${addr:submode}${p}\t${addr:base}, $dsts", + "vldm${addr:submode}${p}\t${addr:base}!, $dsts", "$addr.base = $wb", []> { let Inst{20} = 1; } @@ -102,7 +102,7 @@ def VLDMS_UPD : AXSI5<(outs GPR:$wb), (ins addrmode5:$addr, pred:$p, reglist:$dsts, variable_ops), IndexModeUpd, IIC_fpLoadm, - "vldm${addr:submode}${p}\t${addr:base}, $dsts", + "vldm${addr:submode}${p}\t${addr:base}!, $dsts", "$addr.base = $wb", []> { let Inst{20} = 1; } @@ -124,7 +124,7 @@ def VSTMD_UPD : AXDI5<(outs GPR:$wb), (ins addrmode5:$addr, pred:$p, reglist:$srcs, variable_ops), IndexModeUpd, IIC_fpStorem, - "vstm${addr:submode}${p}\t${addr:base}, $srcs", + "vstm${addr:submode}${p}\t${addr:base}!, $srcs", "$addr.base = $wb", []> { let Inst{20} = 0; } @@ -132,7 +132,7 @@ def VSTMS_UPD : AXSI5<(outs GPR:$wb), (ins addrmode5:$addr, pred:$p, reglist:$srcs, variable_ops), IndexModeUpd, IIC_fpStorem, - "vstm${addr:submode}${p}\t${addr:base}, $srcs", + "vstm${addr:submode}${p}\t${addr:base}!, $srcs", "$addr.base = $wb", []> { let Inst{20} = 0; } Modified: llvm/trunk/lib/Target/ARM/ARMLoadStoreOptimizer.cpp URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Target/ARM/ARMLoadStoreOptimizer.cpp?rev=98648&r1=98647&r2=98648&view=diff ============================================================================== --- llvm/trunk/lib/Target/ARM/ARMLoadStoreOptimizer.cpp (original) +++ llvm/trunk/lib/Target/ARM/ARMLoadStoreOptimizer.cpp Tue Mar 16 13:38:09 2010 @@ -253,7 +253,7 @@ .addImm(ARM_AM::getAM4ModeImm(Mode)).addImm(Pred).addReg(PredReg) : BuildMI(MBB, MBBI, dl, TII->get(Opcode)) .addReg(Base, getKillRegState(BaseKill)) - .addImm(ARM_AM::getAM5Opc(Mode, false, isDPR ? NumRegs<<1 : NumRegs)) + .addImm(ARM_AM::getAM5Opc(Mode, isDPR ? NumRegs<<1 : NumRegs)) .addImm(Pred).addReg(PredReg); for (unsigned i = 0; i != NumRegs; ++i) MIB = MIB.addReg(Regs[i].first, getDefRegState(isDef) @@ -508,7 +508,6 @@ Mode = ARM_AM::getAM4SubMode(MI->getOperand(1).getImm()); } else { // VLDM{D|S}, VSTM{D|S} addressing mode 5 ops. - assert(!ARM_AM::getAM5WBFlag(MI->getOperand(1).getImm())); Mode = ARM_AM::getAM5SubMode(MI->getOperand(1).getImm()); Offset = ARM_AM::getAM5Offset(MI->getOperand(1).getImm()); } @@ -576,7 +575,7 @@ .addImm(Pred).addReg(PredReg); } else { // VLDM[SD}_UPD, VSTM[SD]_UPD - MIB.addImm(ARM_AM::getAM5Opc(Mode, true, Offset)) + MIB.addImm(ARM_AM::getAM5Opc(Mode, Offset)) .addImm(Pred).addReg(PredReg); } // Transfer the rest of operands. @@ -708,7 +707,7 @@ unsigned Offset = 0; if (isAM5) Offset = ARM_AM::getAM5Opc(AddSub == ARM_AM::sub ? ARM_AM::db : ARM_AM::ia, - true, (isDPR ? 2 : 1)); + (isDPR ? 2 : 1)); else if (isAM2) Offset = ARM_AM::getAM2Opc(AddSub, Bytes, ARM_AM::no_shift); else Modified: llvm/trunk/lib/Target/ARM/AsmPrinter/ARMAsmPrinter.cpp URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Target/ARM/AsmPrinter/ARMAsmPrinter.cpp?rev=98648&r1=98647&r2=98648&view=diff ============================================================================== --- llvm/trunk/lib/Target/ARM/AsmPrinter/ARMAsmPrinter.cpp (original) +++ llvm/trunk/lib/Target/ARM/AsmPrinter/ARMAsmPrinter.cpp Tue Mar 16 13:38:09 2010 @@ -546,8 +546,6 @@ } else if (Modifier && strcmp(Modifier, "base") == 0) { // Used for FSTM{D|S} and LSTM{D|S} operations. O << getRegisterName(MO1.getReg()); - if (ARM_AM::getAM5WBFlag(MO2.getImm())) - O << "!"; return; } Modified: llvm/trunk/lib/Target/ARM/AsmPrinter/ARMInstPrinter.cpp URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Target/ARM/AsmPrinter/ARMInstPrinter.cpp?rev=98648&r1=98647&r2=98648&view=diff ============================================================================== --- llvm/trunk/lib/Target/ARM/AsmPrinter/ARMInstPrinter.cpp (original) +++ llvm/trunk/lib/Target/ARM/AsmPrinter/ARMInstPrinter.cpp Tue Mar 16 13:38:09 2010 @@ -252,8 +252,6 @@ } else if (Modifier && strcmp(Modifier, "base") == 0) { // Used for FSTM{D|S} and LSTM{D|S} operations. O << getRegisterName(MO1.getReg()); - if (ARM_AM::getAM5WBFlag(MO2.getImm())) - O << "!"; return; } From clattner at apple.com Tue Mar 16 13:42:17 2010 From: clattner at apple.com (Chris Lattner) Date: Tue, 16 Mar 2010 11:42:17 -0700 Subject: [llvm-commits] [llvm] r98221 - in /llvm/trunk: include/llvm/Target/TargetAsmBackend.h lib/Target/X86/X86AsmBackend.cpp In-Reply-To: <20100311013422.02A942A6C12D@llvm.org> References: <20100311013422.02A942A6C12D@llvm.org> Message-ID: On Mar 10, 2010, at 5:34 PM, Daniel Dunbar wrote: > URL: http://llvm.org/viewvc/llvm-project?rev=98221&view=rev > Log: > MC: Sketch some TargetAsmBackend hooks we are going to need. Hey Daniel, minor point: > +++ llvm/trunk/include/llvm/Target/TargetAsmBackend.h Wed Mar 10 19:34:21 2010 > @@ -28,6 +28,28 @@ > > const Target &getTarget() const { return TheTarget; } ... > > + /// Note that the assembler currently does not reason about atoms, instead it > + /// assumes all temporary symbols reside in the "current atom". > + virtual bool hasScatteredSymbols() const { return false; } For properties input-free predicates like this, instead of using virtual methods, you can just have a field in the class that the subclass initializes, allowing the method to be inline. -Chris From baldrick at free.fr Tue Mar 16 13:50:54 2010 From: baldrick at free.fr (Duncan Sands) Date: Tue, 16 Mar 2010 18:50:54 -0000 Subject: [llvm-commits] [llvm] r98649 - /llvm/trunk/test/FrontendC++/2010-03-16-SinkStores.cpp Message-ID: <20100316185054.EA1D52A6C12C@llvm.org> Author: baldrick Date: Tue Mar 16 13:50:54 2010 New Revision: 98649 URL: http://llvm.org/viewvc/llvm-project?rev=98649&view=rev Log: Chris pointed out that producing undef here is wrong in general. Removed: llvm/trunk/test/FrontendC++/2010-03-16-SinkStores.cpp Removed: llvm/trunk/test/FrontendC++/2010-03-16-SinkStores.cpp URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/FrontendC%2B%2B/2010-03-16-SinkStores.cpp?rev=98648&view=auto ============================================================================== --- llvm/trunk/test/FrontendC++/2010-03-16-SinkStores.cpp (original) +++ llvm/trunk/test/FrontendC++/2010-03-16-SinkStores.cpp (removed) @@ -1,11 +0,0 @@ -// RUN: %llvmgxx -S %s -o - | FileCheck %s - -#include - -typedef std::pair P; -// CHECK: @_ZZ1fvE1X {{.*}} undef - -P f() { - static const P X = P(1,2); - return X; -} From sabre at nondot.org Tue Mar 16 14:07:05 2010 From: sabre at nondot.org (Chris Lattner) Date: Tue, 16 Mar 2010 19:07:05 -0000 Subject: [llvm-commits] [llvm] r98653 - /llvm/trunk/include/llvm/ADT/BitVector.h Message-ID: <20100316190705.80B172A6C12E@llvm.org> Author: lattner Date: Tue Mar 16 14:07:05 2010 New Revision: 98653 URL: http://llvm.org/viewvc/llvm-project?rev=98653&view=rev Log: work around an MSVC2010 bug, PR6504 Modified: llvm/trunk/include/llvm/ADT/BitVector.h Modified: llvm/trunk/include/llvm/ADT/BitVector.h URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/ADT/BitVector.h?rev=98653&r1=98652&r2=98653&view=diff ============================================================================== --- llvm/trunk/include/llvm/ADT/BitVector.h (original) +++ llvm/trunk/include/llvm/ADT/BitVector.h Tue Mar 16 14:07:05 2010 @@ -329,7 +329,8 @@ Size = RHS.size(); unsigned RHSWords = NumBitWords(Size); if (Size <= Capacity * BITWORD_SIZE) { - std::copy(RHS.Bits, &RHS.Bits[RHSWords], Bits); + if (Size) + std::copy(RHS.Bits, &RHS.Bits[RHSWords], Bits); clear_unused_bits(); return *this; } From gohman at apple.com Tue Mar 16 14:08:21 2010 From: gohman at apple.com (Dan Gohman) Date: Tue, 16 Mar 2010 19:08:21 -0000 Subject: [llvm-commits] [llvm] r98654 - /llvm/trunk/test/CodeGen/X86/gather-addresses.ll Message-ID: <20100316190821.0E3FF2A6C12E@llvm.org> Author: djg Date: Tue Mar 16 14:08:20 2010 New Revision: 98654 URL: http://llvm.org/viewvc/llvm-project?rev=98654&view=rev Log: Add an rdar number to this test. Modified: llvm/trunk/test/CodeGen/X86/gather-addresses.ll Modified: llvm/trunk/test/CodeGen/X86/gather-addresses.ll URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/CodeGen/X86/gather-addresses.ll?rev=98654&r1=98653&r2=98654&view=diff ============================================================================== --- llvm/trunk/test/CodeGen/X86/gather-addresses.ll (original) +++ llvm/trunk/test/CodeGen/X86/gather-addresses.ll Tue Mar 16 14:08:20 2010 @@ -1,4 +1,5 @@ ; RUN: llc -march=x86-64 < %s | FileCheck %s +; rdar://7398554 ; When doing vector gather-scatter index calculation with 32-bit indices, ; bounce the vector off of cache rather than shuffling each individual From sabre at nondot.org Tue Mar 16 14:15:04 2010 From: sabre at nondot.org (Chris Lattner) Date: Tue, 16 Mar 2010 19:15:04 -0000 Subject: [llvm-commits] [llvm] r98656 - in /llvm/trunk/lib: Bitcode/Reader/BitcodeReader.cpp Bitcode/Writer/BitcodeWriter.cpp CodeGen/AsmPrinter/AsmPrinter.cpp CodeGen/SelectionDAG/SelectionDAGBuilder.cpp Target/TargetData.cpp Message-ID: <20100316191504.3D7992A6C12C@llvm.org> Author: lattner Date: Tue Mar 16 14:15:03 2010 New Revision: 98656 URL: http://llvm.org/viewvc/llvm-project?rev=98656&view=rev Log: improve support for uniontype and ConstantUnion, patch by Tim Northover! Modified: llvm/trunk/lib/Bitcode/Reader/BitcodeReader.cpp llvm/trunk/lib/Bitcode/Writer/BitcodeWriter.cpp llvm/trunk/lib/CodeGen/AsmPrinter/AsmPrinter.cpp llvm/trunk/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp llvm/trunk/lib/Target/TargetData.cpp Modified: llvm/trunk/lib/Bitcode/Reader/BitcodeReader.cpp URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Bitcode/Reader/BitcodeReader.cpp?rev=98656&r1=98655&r2=98656&view=diff ============================================================================== --- llvm/trunk/lib/Bitcode/Reader/BitcodeReader.cpp (original) +++ llvm/trunk/lib/Bitcode/Reader/BitcodeReader.cpp Tue Mar 16 14:15:03 2010 @@ -293,6 +293,8 @@ } else if (ConstantStruct *UserCS = dyn_cast(UserC)) { NewC = ConstantStruct::get(Context, &NewOps[0], NewOps.size(), UserCS->getType()->isPacked()); + } else if (ConstantUnion *UserCU = dyn_cast(UserC)) { + NewC = ConstantUnion::get(UserCU->getType(), NewOps[0]); } else if (isa(UserC)) { NewC = ConstantVector::get(&NewOps[0], NewOps.size()); } else { @@ -1015,6 +1017,11 @@ Elts.push_back(ValueList.getConstantFwdRef(Record[i], STy->getElementType(i))); V = ConstantStruct::get(STy, Elts); + } else if (const UnionType *UnTy = dyn_cast(CurTy)) { + uint64_t Index = Record[0]; + Constant *Val = ValueList.getConstantFwdRef(Record[1], + UnTy->getElementType(Index)); + V = ConstantUnion::get(UnTy, Val); } else if (const ArrayType *ATy = dyn_cast(CurTy)) { const Type *EltTy = ATy->getElementType(); for (unsigned i = 0; i != Size; ++i) Modified: llvm/trunk/lib/Bitcode/Writer/BitcodeWriter.cpp URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Bitcode/Writer/BitcodeWriter.cpp?rev=98656&r1=98655&r2=98656&view=diff ============================================================================== --- llvm/trunk/lib/Bitcode/Writer/BitcodeWriter.cpp (original) +++ llvm/trunk/lib/Bitcode/Writer/BitcodeWriter.cpp Tue Mar 16 14:15:03 2010 @@ -808,11 +808,25 @@ else if (isCStr7) AbbrevToUse = CString7Abbrev; } else if (isa(C) || isa(V) || - isa(C) || isa(V)) { + isa(V)) { Code = bitc::CST_CODE_AGGREGATE; for (unsigned i = 0, e = C->getNumOperands(); i != e; ++i) Record.push_back(VE.getValueID(C->getOperand(i))); AbbrevToUse = AggregateAbbrev; + } else if (isa(C)) { + Code = bitc::CST_CODE_AGGREGATE; + + // Unions only have one entry but we must send type along with it. + const Type *EntryKind = C->getOperand(0)->getType(); + + const UnionType *UnTy = cast(C->getType()); + int UnionIndex = UnTy->getElementTypeIndex(EntryKind); + assert(UnionIndex != -1 && "Constant union contains invalid entry"); + + Record.push_back(UnionIndex); + Record.push_back(VE.getValueID(C->getOperand(0))); + + AbbrevToUse = AggregateAbbrev; } else if (const ConstantExpr *CE = dyn_cast(C)) { switch (CE->getOpcode()) { default: Modified: llvm/trunk/lib/CodeGen/AsmPrinter/AsmPrinter.cpp URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/CodeGen/AsmPrinter/AsmPrinter.cpp?rev=98656&r1=98655&r2=98656&view=diff ============================================================================== --- llvm/trunk/lib/CodeGen/AsmPrinter/AsmPrinter.cpp (original) +++ llvm/trunk/lib/CodeGen/AsmPrinter/AsmPrinter.cpp Tue Mar 16 14:15:03 2010 @@ -1138,6 +1138,21 @@ "Layout of constant struct may be incorrect!"); } +static void EmitGlobalConstantUnion(const ConstantUnion *CU, + unsigned AddrSpace, AsmPrinter &AP) { + const TargetData *TD = AP.TM.getTargetData(); + unsigned Size = TD->getTypeAllocSize(CU->getType()); + + const Constant *Contents = CU->getOperand(0); + unsigned FilledSize = TD->getTypeAllocSize(Contents->getType()); + + // Print the actually filled part + AP.EmitGlobalConstant(Contents, AddrSpace); + + // And pad with enough zeroes + AP.OutStreamer.EmitZeros(Size-FilledSize, AddrSpace); +} + static void EmitGlobalConstantFP(const ConstantFP *CFP, unsigned AddrSpace, AsmPrinter &AP) { // FP Constants are printed as integer constants to avoid losing @@ -1257,9 +1272,6 @@ if (const ConstantFP *CFP = dyn_cast(CV)) return EmitGlobalConstantFP(CFP, AddrSpace, *this); - - if (const ConstantVector *V = dyn_cast(CV)) - return EmitGlobalConstantVector(V, AddrSpace, *this); if (isa(CV)) { unsigned Size = TM.getTargetData()->getTypeAllocSize(CV->getType()); @@ -1267,6 +1279,12 @@ return; } + if (const ConstantUnion *CVU = dyn_cast(CV)) + return EmitGlobalConstantUnion(CVU, AddrSpace, *this); + + if (const ConstantVector *V = dyn_cast(CV)) + return EmitGlobalConstantVector(V, AddrSpace, *this); + // Otherwise, it must be a ConstantExpr. Lower it to an MCExpr, then emit it // thread the streamer with EmitValue. OutStreamer.EmitValue(LowerConstant(CV, *this), Modified: llvm/trunk/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp?rev=98656&r1=98655&r2=98656&view=diff ============================================================================== --- llvm/trunk/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp (original) +++ llvm/trunk/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp Tue Mar 16 14:15:03 2010 @@ -2592,6 +2592,11 @@ } Ty = StTy->getElementType(Field); + } else if (const UnionType *UnTy = dyn_cast(Ty)) { + unsigned Field = cast(Idx)->getZExtValue(); + + // Offset canonically 0 for unions, but type changes + Ty = UnTy->getElementType(Field); } else { Ty = cast(Ty)->getElementType(); Modified: llvm/trunk/lib/Target/TargetData.cpp URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Target/TargetData.cpp?rev=98656&r1=98655&r2=98656&view=diff ============================================================================== --- llvm/trunk/lib/Target/TargetData.cpp (original) +++ llvm/trunk/lib/Target/TargetData.cpp Tue Mar 16 14:15:03 2010 @@ -460,6 +460,15 @@ case Type::StructTyID: // Get the layout annotation... which is lazily created on demand. return getStructLayout(cast(Ty))->getSizeInBits(); + case Type::UnionTyID: { + const UnionType *UnTy = cast(Ty); + uint64_t Size = 0; + for (UnionType::element_iterator i = UnTy->element_begin(), + e = UnTy->element_end(); i != e; ++i) { + Size = std::max(Size, getTypeSizeInBits(*i)); + } + return Size; + } case Type::IntegerTyID: return cast(Ty)->getBitWidth(); case Type::VoidTyID: @@ -516,6 +525,17 @@ unsigned Align = getAlignmentInfo(AGGREGATE_ALIGN, 0, abi_or_pref, Ty); return std::max(Align, (unsigned)Layout->getAlignment()); } + case Type::UnionTyID: { + const UnionType *UnTy = cast(Ty); + unsigned Align = 1; + + // Unions need the maximum alignment of all their entries + for (UnionType::element_iterator i = UnTy->element_begin(), + e = UnTy->element_end(); i != e; ++i) { + Align = std::max(Align, (unsigned)getAlignment(*i, abi_or_pref)); + } + return Align; + } case Type::IntegerTyID: case Type::VoidTyID: AlignType = INTEGER_ALIGN; @@ -600,6 +620,11 @@ // Update Ty to refer to current element Ty = STy->getElementType(FieldNo); + } else if (const UnionType *UnTy = dyn_cast(*TI)) { + unsigned FieldNo = cast(Indices[CurIDX])->getZExtValue(); + + // Offset into union is canonically 0, but type changes + Ty = UnTy->getElementType(FieldNo); } else { // Update Ty to refer to current element Ty = cast(Ty)->getElementType(); From daniel at zuster.org Tue Mar 16 14:35:35 2010 From: daniel at zuster.org (Daniel Dunbar) Date: Tue, 16 Mar 2010 19:35:35 -0000 Subject: [llvm-commits] [llvm] r98662 - in /llvm/trunk/lib: Bitcode/Reader/BitcodeReader.cpp Bitcode/Writer/BitcodeWriter.cpp CodeGen/AsmPrinter/AsmPrinter.cpp CodeGen/SelectionDAG/SelectionDAGBuilder.cpp Target/TargetData.cpp Message-ID: <20100316193535.233A82A6C12C@llvm.org> Author: ddunbar Date: Tue Mar 16 14:35:34 2010 New Revision: 98662 URL: http://llvm.org/viewvc/llvm-project?rev=98662&view=rev Log: Revert r98656, its breaking all over the place. Modified: llvm/trunk/lib/Bitcode/Reader/BitcodeReader.cpp llvm/trunk/lib/Bitcode/Writer/BitcodeWriter.cpp llvm/trunk/lib/CodeGen/AsmPrinter/AsmPrinter.cpp llvm/trunk/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp llvm/trunk/lib/Target/TargetData.cpp Modified: llvm/trunk/lib/Bitcode/Reader/BitcodeReader.cpp URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Bitcode/Reader/BitcodeReader.cpp?rev=98662&r1=98661&r2=98662&view=diff ============================================================================== --- llvm/trunk/lib/Bitcode/Reader/BitcodeReader.cpp (original) +++ llvm/trunk/lib/Bitcode/Reader/BitcodeReader.cpp Tue Mar 16 14:35:34 2010 @@ -293,8 +293,6 @@ } else if (ConstantStruct *UserCS = dyn_cast(UserC)) { NewC = ConstantStruct::get(Context, &NewOps[0], NewOps.size(), UserCS->getType()->isPacked()); - } else if (ConstantUnion *UserCU = dyn_cast(UserC)) { - NewC = ConstantUnion::get(UserCU->getType(), NewOps[0]); } else if (isa(UserC)) { NewC = ConstantVector::get(&NewOps[0], NewOps.size()); } else { @@ -1017,11 +1015,6 @@ Elts.push_back(ValueList.getConstantFwdRef(Record[i], STy->getElementType(i))); V = ConstantStruct::get(STy, Elts); - } else if (const UnionType *UnTy = dyn_cast(CurTy)) { - uint64_t Index = Record[0]; - Constant *Val = ValueList.getConstantFwdRef(Record[1], - UnTy->getElementType(Index)); - V = ConstantUnion::get(UnTy, Val); } else if (const ArrayType *ATy = dyn_cast(CurTy)) { const Type *EltTy = ATy->getElementType(); for (unsigned i = 0; i != Size; ++i) Modified: llvm/trunk/lib/Bitcode/Writer/BitcodeWriter.cpp URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Bitcode/Writer/BitcodeWriter.cpp?rev=98662&r1=98661&r2=98662&view=diff ============================================================================== --- llvm/trunk/lib/Bitcode/Writer/BitcodeWriter.cpp (original) +++ llvm/trunk/lib/Bitcode/Writer/BitcodeWriter.cpp Tue Mar 16 14:35:34 2010 @@ -808,25 +808,11 @@ else if (isCStr7) AbbrevToUse = CString7Abbrev; } else if (isa(C) || isa(V) || - isa(V)) { + isa(C) || isa(V)) { Code = bitc::CST_CODE_AGGREGATE; for (unsigned i = 0, e = C->getNumOperands(); i != e; ++i) Record.push_back(VE.getValueID(C->getOperand(i))); AbbrevToUse = AggregateAbbrev; - } else if (isa(C)) { - Code = bitc::CST_CODE_AGGREGATE; - - // Unions only have one entry but we must send type along with it. - const Type *EntryKind = C->getOperand(0)->getType(); - - const UnionType *UnTy = cast(C->getType()); - int UnionIndex = UnTy->getElementTypeIndex(EntryKind); - assert(UnionIndex != -1 && "Constant union contains invalid entry"); - - Record.push_back(UnionIndex); - Record.push_back(VE.getValueID(C->getOperand(0))); - - AbbrevToUse = AggregateAbbrev; } else if (const ConstantExpr *CE = dyn_cast(C)) { switch (CE->getOpcode()) { default: Modified: llvm/trunk/lib/CodeGen/AsmPrinter/AsmPrinter.cpp URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/CodeGen/AsmPrinter/AsmPrinter.cpp?rev=98662&r1=98661&r2=98662&view=diff ============================================================================== --- llvm/trunk/lib/CodeGen/AsmPrinter/AsmPrinter.cpp (original) +++ llvm/trunk/lib/CodeGen/AsmPrinter/AsmPrinter.cpp Tue Mar 16 14:35:34 2010 @@ -1138,21 +1138,6 @@ "Layout of constant struct may be incorrect!"); } -static void EmitGlobalConstantUnion(const ConstantUnion *CU, - unsigned AddrSpace, AsmPrinter &AP) { - const TargetData *TD = AP.TM.getTargetData(); - unsigned Size = TD->getTypeAllocSize(CU->getType()); - - const Constant *Contents = CU->getOperand(0); - unsigned FilledSize = TD->getTypeAllocSize(Contents->getType()); - - // Print the actually filled part - AP.EmitGlobalConstant(Contents, AddrSpace); - - // And pad with enough zeroes - AP.OutStreamer.EmitZeros(Size-FilledSize, AddrSpace); -} - static void EmitGlobalConstantFP(const ConstantFP *CFP, unsigned AddrSpace, AsmPrinter &AP) { // FP Constants are printed as integer constants to avoid losing @@ -1272,6 +1257,9 @@ if (const ConstantFP *CFP = dyn_cast(CV)) return EmitGlobalConstantFP(CFP, AddrSpace, *this); + + if (const ConstantVector *V = dyn_cast(CV)) + return EmitGlobalConstantVector(V, AddrSpace, *this); if (isa(CV)) { unsigned Size = TM.getTargetData()->getTypeAllocSize(CV->getType()); @@ -1279,12 +1267,6 @@ return; } - if (const ConstantUnion *CVU = dyn_cast(CV)) - return EmitGlobalConstantUnion(CVU, AddrSpace, *this); - - if (const ConstantVector *V = dyn_cast(CV)) - return EmitGlobalConstantVector(V, AddrSpace, *this); - // Otherwise, it must be a ConstantExpr. Lower it to an MCExpr, then emit it // thread the streamer with EmitValue. OutStreamer.EmitValue(LowerConstant(CV, *this), Modified: llvm/trunk/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp?rev=98662&r1=98661&r2=98662&view=diff ============================================================================== --- llvm/trunk/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp (original) +++ llvm/trunk/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp Tue Mar 16 14:35:34 2010 @@ -2592,11 +2592,6 @@ } Ty = StTy->getElementType(Field); - } else if (const UnionType *UnTy = dyn_cast(Ty)) { - unsigned Field = cast(Idx)->getZExtValue(); - - // Offset canonically 0 for unions, but type changes - Ty = UnTy->getElementType(Field); } else { Ty = cast(Ty)->getElementType(); Modified: llvm/trunk/lib/Target/TargetData.cpp URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Target/TargetData.cpp?rev=98662&r1=98661&r2=98662&view=diff ============================================================================== --- llvm/trunk/lib/Target/TargetData.cpp (original) +++ llvm/trunk/lib/Target/TargetData.cpp Tue Mar 16 14:35:34 2010 @@ -460,15 +460,6 @@ case Type::StructTyID: // Get the layout annotation... which is lazily created on demand. return getStructLayout(cast(Ty))->getSizeInBits(); - case Type::UnionTyID: { - const UnionType *UnTy = cast(Ty); - uint64_t Size = 0; - for (UnionType::element_iterator i = UnTy->element_begin(), - e = UnTy->element_end(); i != e; ++i) { - Size = std::max(Size, getTypeSizeInBits(*i)); - } - return Size; - } case Type::IntegerTyID: return cast(Ty)->getBitWidth(); case Type::VoidTyID: @@ -525,17 +516,6 @@ unsigned Align = getAlignmentInfo(AGGREGATE_ALIGN, 0, abi_or_pref, Ty); return std::max(Align, (unsigned)Layout->getAlignment()); } - case Type::UnionTyID: { - const UnionType *UnTy = cast(Ty); - unsigned Align = 1; - - // Unions need the maximum alignment of all their entries - for (UnionType::element_iterator i = UnTy->element_begin(), - e = UnTy->element_end(); i != e; ++i) { - Align = std::max(Align, (unsigned)getAlignment(*i, abi_or_pref)); - } - return Align; - } case Type::IntegerTyID: case Type::VoidTyID: AlignType = INTEGER_ALIGN; @@ -620,11 +600,6 @@ // Update Ty to refer to current element Ty = STy->getElementType(FieldNo); - } else if (const UnionType *UnTy = dyn_cast(*TI)) { - unsigned FieldNo = cast(Indices[CurIDX])->getZExtValue(); - - // Offset into union is canonically 0, but type changes - Ty = UnTy->getElementType(FieldNo); } else { // Update Ty to refer to current element Ty = cast(Ty)->getElementType(); From benny.kra at googlemail.com Tue Mar 16 14:36:43 2010 From: benny.kra at googlemail.com (Benjamin Kramer) Date: Tue, 16 Mar 2010 19:36:43 -0000 Subject: [llvm-commits] [llvm] r98663 - /llvm/trunk/lib/Transforms/Scalar/SimplifyLibCalls.cpp Message-ID: <20100316193643.5A7102A6C12C@llvm.org> Author: d0k Date: Tue Mar 16 14:36:43 2010 New Revision: 98663 URL: http://llvm.org/viewvc/llvm-project?rev=98663&view=rev Log: Mark str[r]chr readonly. Modified: llvm/trunk/lib/Transforms/Scalar/SimplifyLibCalls.cpp Modified: llvm/trunk/lib/Transforms/Scalar/SimplifyLibCalls.cpp URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Transforms/Scalar/SimplifyLibCalls.cpp?rev=98663&r1=98662&r2=98663&view=diff ============================================================================== --- llvm/trunk/lib/Transforms/Scalar/SimplifyLibCalls.cpp (original) +++ llvm/trunk/lib/Transforms/Scalar/SimplifyLibCalls.cpp Tue Mar 16 14:36:43 2010 @@ -1400,6 +1400,15 @@ setOnlyReadsMemory(F); setDoesNotThrow(F); setDoesNotCapture(F, 1); + } else if (Name == "strchr" || + Name == "strrchr") { + if (FTy->getNumParams() != 2 || + !FTy->getParamType(0)->isPointerTy() || + !FTy->getParamType(1)->isIntegerTy()) + continue; + setOnlyReadsMemory(F); + setDoesNotThrow(F); + setDoesNotCapture(F, 1); } else if (Name == "strcpy" || Name == "stpcpy" || Name == "strcat" || @@ -1428,7 +1437,7 @@ } else if (Name == "strcmp" || Name == "strspn" || Name == "strncmp" || - Name ==" strcspn" || + Name == "strcspn" || Name == "strcoll" || Name == "strcasecmp" || Name == "strncasecmp") { From sabre at nondot.org Tue Mar 16 15:08:07 2010 From: sabre at nondot.org (Chris Lattner) Date: Tue, 16 Mar 2010 20:08:07 -0000 Subject: [llvm-commits] [llvm] r98666 - /llvm/trunk/test/Feature/unions.ll Message-ID: <20100316200807.7AFF42A6C12C@llvm.org> Author: lattner Date: Tue Mar 16 15:08:07 2010 New Revision: 98666 URL: http://llvm.org/viewvc/llvm-project?rev=98666&view=rev Log: temporarily xfail Modified: llvm/trunk/test/Feature/unions.ll Modified: llvm/trunk/test/Feature/unions.ll URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Feature/unions.ll?rev=98666&r1=98665&r2=98666&view=diff ============================================================================== --- llvm/trunk/test/Feature/unions.ll (original) +++ llvm/trunk/test/Feature/unions.ll Tue Mar 16 15:08:07 2010 @@ -1,7 +1,7 @@ ; RUN: llvm-as < %s | llvm-dis > %t1.ll ; RUN: llvm-as %t1.ll -o - | llvm-dis > %t2.ll ; RUN: diff %t1.ll %t2.ll - +; XFAIL: * %union.anon = type union { i8, i32, float } @union1 = constant union { i32, i8 } { i32 4 } From baldrick at free.fr Tue Mar 16 15:10:57 2010 From: baldrick at free.fr (Duncan Sands) Date: Tue, 16 Mar 2010 21:10:57 +0100 Subject: [llvm-commits] [llvm-gcc-4.2] r98626 - /llvm-gcc-4.2/trunk/gcc/llvm-backend.cpp In-Reply-To: <845F2FE3-4DAD-4E9B-9696-1536660633CE@apple.com> References: <20100316113532.C19AA2A6C12C@llvm.org> <1DFD651D-2FC7-46B9-AC95-C72E7AB183D7@apple.com> <4B9FCAD2.4060405@free.fr> <845F2FE3-4DAD-4E9B-9696-1536660633CE@apple.com> Message-ID: <4B9FE5D1.903@free.fr> On 16/03/10 19:18, Chris Lattner wrote: > On Mar 16, 2010, at 11:15 AM, Duncan Sands wrote: >>> I originally tried to do this for llvm-gcc 3 and was defeated by libstdc++. It assumes (and it turns out the c++ standard allows this) that global variables are zero initialized before the constructor for a type is run on it. >> >> That is so annoying! You could do easily do some nice simplifications if this >> wasn't the case... > > Yeah I know. I assume you noticed the globalopt xforms that build on this. I added those back when I thought that the c++ frontend could take advantage of it, then had to revert the frontend changes. Actually those globalopt transforms are still useful - for Ada. In Ada a global variable without an explicit initializer is not implicitly zero-initialized, it is simply uninitialized (undef). Ciao, Duncan. From baldrick at free.fr Tue Mar 16 15:15:37 2010 From: baldrick at free.fr (Duncan Sands) Date: Tue, 16 Mar 2010 21:15:37 +0100 Subject: [llvm-commits] [llvm] r98663 - /llvm/trunk/lib/Transforms/Scalar/SimplifyLibCalls.cpp In-Reply-To: <20100316193643.5A7102A6C12C@llvm.org> References: <20100316193643.5A7102A6C12C@llvm.org> Message-ID: <4B9FE6E9.3020709@free.fr> Hi Benjamin, > + } else if (Name == "strchr" || > + Name == "strrchr") { > + if (FTy->getNumParams() != 2 || > + !FTy->getParamType(0)->isPointerTy() || > + !FTy->getParamType(1)->isIntegerTy()) > + continue; > + setOnlyReadsMemory(F); > + setDoesNotThrow(F); > + setDoesNotCapture(F, 1); since strchr returns its pointer argument (offset a bit, usually), that means that it is captured. Ciao, Duncan. From benny.kra at googlemail.com Tue Mar 16 15:33:15 2010 From: benny.kra at googlemail.com (Benjamin Kramer) Date: Tue, 16 Mar 2010 20:33:15 -0000 Subject: [llvm-commits] [llvm] r98671 - /llvm/trunk/lib/Transforms/Scalar/SimplifyLibCalls.cpp Message-ID: <20100316203316.030992A6C12C@llvm.org> Author: d0k Date: Tue Mar 16 15:33:15 2010 New Revision: 98671 URL: http://llvm.org/viewvc/llvm-project?rev=98671&view=rev Log: str[r]chr returns its pointer argument so we cannot mark it as nocapture. Thanks to Duncan for spotting my mistake. Modified: llvm/trunk/lib/Transforms/Scalar/SimplifyLibCalls.cpp Modified: llvm/trunk/lib/Transforms/Scalar/SimplifyLibCalls.cpp URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Transforms/Scalar/SimplifyLibCalls.cpp?rev=98671&r1=98670&r2=98671&view=diff ============================================================================== --- llvm/trunk/lib/Transforms/Scalar/SimplifyLibCalls.cpp (original) +++ llvm/trunk/lib/Transforms/Scalar/SimplifyLibCalls.cpp Tue Mar 16 15:33:15 2010 @@ -1408,7 +1408,6 @@ continue; setOnlyReadsMemory(F); setDoesNotThrow(F); - setDoesNotCapture(F, 1); } else if (Name == "strcpy" || Name == "stpcpy" || Name == "strcat" || From benny.kra at googlemail.com Tue Mar 16 15:35:03 2010 From: benny.kra at googlemail.com (Benjamin Kramer) Date: Tue, 16 Mar 2010 21:35:03 +0100 Subject: [llvm-commits] [llvm] r98663 - /llvm/trunk/lib/Transforms/Scalar/SimplifyLibCalls.cpp In-Reply-To: <4B9FE6E9.3020709@free.fr> References: <20100316193643.5A7102A6C12C@llvm.org> <4B9FE6E9.3020709@free.fr> Message-ID: <348828F1-E4B8-467A-913C-8052B9A26605@gmail.com> On 16.03.2010, at 21:15, Duncan Sands wrote: > Hi Benjamin, > >> + } else if (Name == "strchr" || >> + Name == "strrchr") { >> + if (FTy->getNumParams() != 2 || >> + !FTy->getParamType(0)->isPointerTy() || >> + !FTy->getParamType(1)->isIntegerTy()) >> + continue; >> + setOnlyReadsMemory(F); >> + setDoesNotThrow(F); >> + setDoesNotCapture(F, 1); > > since strchr returns its pointer argument (offset a bit, usually), that > means that it is captured. Oops, fixed in r98671. From daniel at zuster.org Tue Mar 16 15:52:59 2010 From: daniel at zuster.org (Daniel Dunbar) Date: Tue, 16 Mar 2010 20:52:59 -0000 Subject: [llvm-commits] [llvm] r98673 - /llvm/trunk/test/Feature/unions.ll Message-ID: <20100316205259.AE9C32A6C12C@llvm.org> Author: ddunbar Date: Tue Mar 16 15:52:59 2010 New Revision: 98673 URL: http://llvm.org/viewvc/llvm-project?rev=98673&view=rev Log: Revert r98666 too; it's checkin-without-testing day! Modified: llvm/trunk/test/Feature/unions.ll Modified: llvm/trunk/test/Feature/unions.ll URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Feature/unions.ll?rev=98673&r1=98672&r2=98673&view=diff ============================================================================== --- llvm/trunk/test/Feature/unions.ll (original) +++ llvm/trunk/test/Feature/unions.ll Tue Mar 16 15:52:59 2010 @@ -1,7 +1,7 @@ ; RUN: llvm-as < %s | llvm-dis > %t1.ll ; RUN: llvm-as %t1.ll -o - | llvm-dis > %t2.ll ; RUN: diff %t1.ll %t2.ll -; XFAIL: * + %union.anon = type union { i8, i32, float } @union1 = constant union { i32, i8 } { i32 4 } From daniel at zuster.org Tue Mar 16 15:56:55 2010 From: daniel at zuster.org (Daniel Dunbar) Date: Tue, 16 Mar 2010 13:56:55 -0700 Subject: [llvm-commits] [llvm] r98666 - /llvm/trunk/test/Feature/unions.ll In-Reply-To: <20100316200807.7AFF42A6C12C@llvm.org> References: <20100316200807.7AFF42A6C12C@llvm.org> Message-ID: <6a8523d61003161356i7eaea2d3x7dc1d8602fd66cb6@mail.gmail.com> This was the wrong solution, (a) because I already reverted the patch, and (b) because it doesn't make sense to XFAIL a test which only started failing by a commit to exactly-that-which-it-is-testing. Reverting the initial patch is more reasonable, which would also have nicely given you a friendly svn conflict. :) - Daniel On Tue, Mar 16, 2010 at 1:08 PM, Chris Lattner wrote: > Author: lattner > Date: Tue Mar 16 15:08:07 2010 > New Revision: 98666 > > URL: http://llvm.org/viewvc/llvm-project?rev=98666&view=rev > Log: > temporarily xfail > > Modified: > ? ?llvm/trunk/test/Feature/unions.ll > > Modified: llvm/trunk/test/Feature/unions.ll > URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Feature/unions.ll?rev=98666&r1=98665&r2=98666&view=diff > ============================================================================== > --- llvm/trunk/test/Feature/unions.ll (original) > +++ llvm/trunk/test/Feature/unions.ll Tue Mar 16 15:08:07 2010 > @@ -1,7 +1,7 @@ > ?; RUN: llvm-as < %s | llvm-dis > %t1.ll > ?; RUN: llvm-as %t1.ll -o - | llvm-dis > %t2.ll > ?; RUN: diff %t1.ll %t2.ll > - > +; XFAIL: * > ?%union.anon = type union { i8, i32, float } > > ?@union1 = constant union { i32, i8 } { i32 4 } > > > _______________________________________________ > llvm-commits mailing list > llvm-commits at cs.uiuc.edu > http://lists.cs.uiuc.edu/mailman/listinfo/llvm-commits > From sabre at nondot.org Tue Mar 16 15:58:36 2010 From: sabre at nondot.org (Chris Lattner) Date: Tue, 16 Mar 2010 13:58:36 -0700 Subject: [llvm-commits] [llvm] r98666 - /llvm/trunk/test/Feature/unions.ll In-Reply-To: <6a8523d61003161356i7eaea2d3x7dc1d8602fd66cb6@mail.gmail.com> References: <20100316200807.7AFF42A6C12C@llvm.org> <6a8523d61003161356i7eaea2d3x7dc1d8602fd66cb6@mail.gmail.com> Message-ID: Sorry, I missed your revert. I tested my xfail locally before committing it. Unions are half baked anyway, I wasn't worried about breaking them. -Chris On Mar 16, 2010, at 1:56 PM, Daniel Dunbar wrote: > This was the wrong solution, (a) because I already reverted the patch, > and (b) because it doesn't make sense to XFAIL a test which only > started failing by a commit to exactly-that-which-it-is-testing. > Reverting the initial patch is more reasonable, which would also have > nicely given you a friendly svn conflict. :) > > - Daniel > > On Tue, Mar 16, 2010 at 1:08 PM, Chris Lattner wrote: >> Author: lattner >> Date: Tue Mar 16 15:08:07 2010 >> New Revision: 98666 >> >> URL: http://llvm.org/viewvc/llvm-project?rev=98666&view=rev >> Log: >> temporarily xfail >> >> Modified: >> llvm/trunk/test/Feature/unions.ll >> >> Modified: llvm/trunk/test/Feature/unions.ll >> URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Feature/unions.ll?rev=98666&r1=98665&r2=98666&view=diff >> ============================================================================== >> --- llvm/trunk/test/Feature/unions.ll (original) >> +++ llvm/trunk/test/Feature/unions.ll Tue Mar 16 15:08:07 2010 >> @@ -1,7 +1,7 @@ >> ; RUN: llvm-as < %s | llvm-dis > %t1.ll >> ; RUN: llvm-as %t1.ll -o - | llvm-dis > %t2.ll >> ; RUN: diff %t1.ll %t2.ll >> - >> +; XFAIL: * >> %union.anon = type union { i8, i32, float } >> >> @union1 = constant union { i32, i8 } { i32 4 } >> >> >> _______________________________________________ >> llvm-commits mailing list >> llvm-commits at cs.uiuc.edu >> http://lists.cs.uiuc.edu/mailman/listinfo/llvm-commits >> > > _______________________________________________ > llvm-commits mailing list > llvm-commits at cs.uiuc.edu > http://lists.cs.uiuc.edu/mailman/listinfo/llvm-commits From dpatel at apple.com Tue Mar 16 16:02:07 2010 From: dpatel at apple.com (Devang Patel) Date: Tue, 16 Mar 2010 21:02:07 -0000 Subject: [llvm-commits] [llvm] r98675 - /llvm/trunk/lib/CodeGen/TailDuplication.cpp Message-ID: <20100316210207.A6C292A6C12C@llvm.org> Author: dpatel Date: Tue Mar 16 16:02:07 2010 New Revision: 98675 URL: http://llvm.org/viewvc/llvm-project?rev=98675&view=rev Log: Ignore debug value instructions while analyzing BB for tail duplication. Modified: llvm/trunk/lib/CodeGen/TailDuplication.cpp Modified: llvm/trunk/lib/CodeGen/TailDuplication.cpp URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/CodeGen/TailDuplication.cpp?rev=98675&r1=98674&r2=98675&view=diff ============================================================================== --- llvm/trunk/lib/CodeGen/TailDuplication.cpp (original) +++ llvm/trunk/lib/CodeGen/TailDuplication.cpp Tue Mar 16 16:02:07 2010 @@ -495,7 +495,7 @@ if (InstrCount == MaxDuplicateCount) return false; // Remember if we saw a call. if (I->getDesc().isCall()) HasCall = true; - if (!I->isPHI()) + if (!I->isPHI() && !I->isDebugValue()) InstrCount += 1; } // Heuristically, don't tail-duplicate calls if it would expand code size, From clattner at apple.com Tue Mar 16 16:10:10 2010 From: clattner at apple.com (Chris Lattner) Date: Tue, 16 Mar 2010 14:10:10 -0700 Subject: [llvm-commits] [llvm] r98666 - /llvm/trunk/test/Feature/unions.ll In-Reply-To: References: <20100316200807.7AFF42A6C12C@llvm.org> <6a8523d61003161356i7eaea2d3x7dc1d8602fd66cb6@mail.gmail.com> Message-ID: FYI, unions.ll is completely broken on mainline also, the test just happens to not catch it due to how it's written. $ llvm-as < unions.ll | llvm-dis %union.anon = type union { i8, i32, float } @union1 = constant union { i32, i8 } undef ; [#uses=0] @union2 = constant union { i32, i8 } undef ; [#uses=0] -Chris On Mar 16, 2010, at 1:58 PM, Chris Lattner wrote: > Sorry, I missed your revert. I tested my xfail locally before committing it. > > Unions are half baked anyway, I wasn't worried about breaking them. > > -Chris > > On Mar 16, 2010, at 1:56 PM, Daniel Dunbar wrote: > >> This was the wrong solution, (a) because I already reverted the patch, >> and (b) because it doesn't make sense to XFAIL a test which only >> started failing by a commit to exactly-that-which-it-is-testing. >> Reverting the initial patch is more reasonable, which would also have >> nicely given you a friendly svn conflict. :) >> >> - Daniel >> >> On Tue, Mar 16, 2010 at 1:08 PM, Chris Lattner wrote: >>> Author: lattner >>> Date: Tue Mar 16 15:08:07 2010 >>> New Revision: 98666 >>> >>> URL: http://llvm.org/viewvc/llvm-project?rev=98666&view=rev >>> Log: >>> temporarily xfail >>> >>> Modified: >>> llvm/trunk/test/Feature/unions.ll >>> >>> Modified: llvm/trunk/test/Feature/unions.ll >>> URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Feature/unions.ll?rev=98666&r1=98665&r2=98666&view=diff >>> ============================================================================== >>> --- llvm/trunk/test/Feature/unions.ll (original) >>> +++ llvm/trunk/test/Feature/unions.ll Tue Mar 16 15:08:07 2010 >>> @@ -1,7 +1,7 @@ >>> ; RUN: llvm-as < %s | llvm-dis > %t1.ll >>> ; RUN: llvm-as %t1.ll -o - | llvm-dis > %t2.ll >>> ; RUN: diff %t1.ll %t2.ll >>> - >>> +; XFAIL: * >>> %union.anon = type union { i8, i32, float } >>> >>> @union1 = constant union { i32, i8 } { i32 4 } >>> >>> >>> _______________________________________________ >>> llvm-commits mailing list >>> llvm-commits at cs.uiuc.edu >>> http://lists.cs.uiuc.edu/mailman/listinfo/llvm-commits >>> >> >> _______________________________________________ >> llvm-commits mailing list >> llvm-commits at cs.uiuc.edu >> http://lists.cs.uiuc.edu/mailman/listinfo/llvm-commits > > > _______________________________________________ > llvm-commits mailing list > llvm-commits at cs.uiuc.edu > http://lists.cs.uiuc.edu/mailman/listinfo/llvm-commits From sabre at nondot.org Tue Mar 16 16:21:35 2010 From: sabre at nondot.org (Chris Lattner) Date: Tue, 16 Mar 2010 21:21:35 -0000 Subject: [llvm-commits] [llvm] r98677 - /llvm/trunk/lib/VMCore/AsmWriter.cpp Message-ID: <20100316212135.E78C12A6C12C@llvm.org> Author: lattner Date: Tue Mar 16 16:21:35 2010 New Revision: 98677 URL: http://llvm.org/viewvc/llvm-project?rev=98677&view=rev Log: add asmprinter suport for unions, fixing Feature/unions.ll to actually be doing something useful. Modified: llvm/trunk/lib/VMCore/AsmWriter.cpp Modified: llvm/trunk/lib/VMCore/AsmWriter.cpp URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/VMCore/AsmWriter.cpp?rev=98677&r1=98676&r2=98677&view=diff ============================================================================== --- llvm/trunk/lib/VMCore/AsmWriter.cpp (original) +++ llvm/trunk/lib/VMCore/AsmWriter.cpp Tue Mar 16 16:21:35 2010 @@ -1027,6 +1027,15 @@ return; } + if (const ConstantUnion *CU = dyn_cast(CV)) { + Out << "{ "; + TypePrinter.print(CU->getOperand(0)->getType(), Out); + Out << ' '; + WriteAsOperandInternal(Out, CU->getOperand(0), &TypePrinter, Machine); + Out << " }"; + return; + } + if (const ConstantVector *CP = dyn_cast(CV)) { const Type *ETy = CP->getType()->getElementType(); assert(CP->getNumOperands() > 0 && From clattner at apple.com Tue Mar 16 16:23:26 2010 From: clattner at apple.com (Chris Lattner) Date: Tue, 16 Mar 2010 14:23:26 -0700 Subject: [llvm-commits] [llvm-gcc-4.2] r98626 - /llvm-gcc-4.2/trunk/gcc/llvm-backend.cpp In-Reply-To: <4B9FE5D1.903@free.fr> References: <20100316113532.C19AA2A6C12C@llvm.org> <1DFD651D-2FC7-46B9-AC95-C72E7AB183D7@apple.com> <4B9FCAD2.4060405@free.fr> <845F2FE3-4DAD-4E9B-9696-1536660633CE@apple.com> <4B9FE5D1.903@free.fr> Message-ID: On Mar 16, 2010, at 1:10 PM, Duncan Sands wrote: > On 16/03/10 19:18, Chris Lattner wrote: >> On Mar 16, 2010, at 11:15 AM, Duncan Sands wrote: >>>> I originally tried to do this for llvm-gcc 3 and was defeated by libstdc++. It assumes (and it turns out the c++ standard allows this) that global variables are zero initialized before the constructor for a type is run on it. >>> >>> That is so annoying! You could do easily do some nice simplifications if this >>> wasn't the case... >> >> Yeah I know. I assume you noticed the globalopt xforms that build on this. I added those back when I thought that the c++ frontend could take advantage of it, then had to revert the frontend changes. > > Actually those globalopt transforms are still useful - for Ada. In Ada a global > variable without an explicit initializer is not implicitly zero-initialized, it > is simply uninitialized (undef). Yep, that's why I didn't remove them :) -Chris From johnny.chen at apple.com Tue Mar 16 16:25:06 2010 From: johnny.chen at apple.com (Johnny Chen) Date: Tue, 16 Mar 2010 21:25:06 -0000 Subject: [llvm-commits] [llvm] r98679 - in /llvm/trunk/lib/Target/ARM: ARMInstrInfo.td ARMInstrVFP.td Message-ID: <20100316212506.1176A2A6C12C@llvm.org> Author: johnny Date: Tue Mar 16 16:25:05 2010 New Revision: 98679 URL: http://llvm.org/viewvc/llvm-project?rev=98679&view=rev Log: Disambiguate the *_UPD and * variants by specifying the writeback flag as 1. This is for the disassembly work. There are cases where this is not possible, for example, A8.6.53 LDM Encoding T1. In such case, we'll use an adhoc approach to deduce the Opcode programmatically. Modified: llvm/trunk/lib/Target/ARM/ARMInstrInfo.td llvm/trunk/lib/Target/ARM/ARMInstrVFP.td Modified: llvm/trunk/lib/Target/ARM/ARMInstrInfo.td URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Target/ARM/ARMInstrInfo.td?rev=98679&r1=98678&r2=98679&view=diff ============================================================================== --- llvm/trunk/lib/Target/ARM/ARMInstrInfo.td (original) +++ llvm/trunk/lib/Target/ARM/ARMInstrInfo.td Tue Mar 16 16:25:05 2010 @@ -1355,7 +1355,9 @@ reglist:$dsts, variable_ops), IndexModeUpd, LdStMulFrm, IIC_iLoadm, "ldm${addr:submode}${p}\t$addr!, $dsts", - "$addr.addr = $wb", []>; + "$addr.addr = $wb", []> { + let Inst{21} = 1; // wback +} } // mayLoad, hasExtraDefRegAllocReq let mayStore = 1, hasExtraSrcRegAllocReq = 1 in { @@ -1368,7 +1370,9 @@ reglist:$srcs, variable_ops), IndexModeUpd, LdStMulFrm, IIC_iStorem, "stm${addr:submode}${p}\t$addr!, $srcs", - "$addr.addr = $wb", []>; + "$addr.addr = $wb", []> { + let Inst{21} = 1; // wback +} } // mayStore, hasExtraSrcRegAllocReq //===----------------------------------------------------------------------===// Modified: llvm/trunk/lib/Target/ARM/ARMInstrVFP.td URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Target/ARM/ARMInstrVFP.td?rev=98679&r1=98678&r2=98679&view=diff ============================================================================== --- llvm/trunk/lib/Target/ARM/ARMInstrVFP.td (original) +++ llvm/trunk/lib/Target/ARM/ARMInstrVFP.td Tue Mar 16 16:25:05 2010 @@ -96,6 +96,7 @@ IndexModeUpd, IIC_fpLoadm, "vldm${addr:submode}${p}\t${addr:base}!, $dsts", "$addr.base = $wb", []> { + let Inst{21} = 1; // wback let Inst{20} = 1; } @@ -104,6 +105,7 @@ IndexModeUpd, IIC_fpLoadm, "vldm${addr:submode}${p}\t${addr:base}!, $dsts", "$addr.base = $wb", []> { + let Inst{21} = 1; // wback let Inst{20} = 1; } } // mayLoad, hasExtraDefRegAllocReq @@ -126,6 +128,7 @@ IndexModeUpd, IIC_fpStorem, "vstm${addr:submode}${p}\t${addr:base}!, $srcs", "$addr.base = $wb", []> { + let Inst{21} = 1; // wback let Inst{20} = 0; } @@ -134,6 +137,7 @@ IndexModeUpd, IIC_fpStorem, "vstm${addr:submode}${p}\t${addr:base}!, $srcs", "$addr.base = $wb", []> { + let Inst{21} = 1; // wback let Inst{20} = 0; } } // mayStore, hasExtraSrcRegAllocReq From sabre at nondot.org Tue Mar 16 16:25:55 2010 From: sabre at nondot.org (Chris Lattner) Date: Tue, 16 Mar 2010 21:25:55 -0000 Subject: [llvm-commits] [llvm] r98680 - in /llvm/trunk/lib: Bitcode/Reader/BitcodeReader.cpp Bitcode/Writer/BitcodeWriter.cpp CodeGen/AsmPrinter/AsmPrinter.cpp CodeGen/SelectionDAG/SelectionDAGBuilder.cpp Target/TargetData.cpp Message-ID: <20100316212555.F13F42A6C12C@llvm.org> Author: lattner Date: Tue Mar 16 16:25:55 2010 New Revision: 98680 URL: http://llvm.org/viewvc/llvm-project?rev=98680&view=rev Log: reapply r98656 unmodified, which exposed the asmprinter not handling constant unions. Modified: llvm/trunk/lib/Bitcode/Reader/BitcodeReader.cpp llvm/trunk/lib/Bitcode/Writer/BitcodeWriter.cpp llvm/trunk/lib/CodeGen/AsmPrinter/AsmPrinter.cpp llvm/trunk/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp llvm/trunk/lib/Target/TargetData.cpp Modified: llvm/trunk/lib/Bitcode/Reader/BitcodeReader.cpp URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Bitcode/Reader/BitcodeReader.cpp?rev=98680&r1=98679&r2=98680&view=diff ============================================================================== --- llvm/trunk/lib/Bitcode/Reader/BitcodeReader.cpp (original) +++ llvm/trunk/lib/Bitcode/Reader/BitcodeReader.cpp Tue Mar 16 16:25:55 2010 @@ -293,6 +293,8 @@ } else if (ConstantStruct *UserCS = dyn_cast(UserC)) { NewC = ConstantStruct::get(Context, &NewOps[0], NewOps.size(), UserCS->getType()->isPacked()); + } else if (ConstantUnion *UserCU = dyn_cast(UserC)) { + NewC = ConstantUnion::get(UserCU->getType(), NewOps[0]); } else if (isa(UserC)) { NewC = ConstantVector::get(&NewOps[0], NewOps.size()); } else { @@ -1015,6 +1017,11 @@ Elts.push_back(ValueList.getConstantFwdRef(Record[i], STy->getElementType(i))); V = ConstantStruct::get(STy, Elts); + } else if (const UnionType *UnTy = dyn_cast(CurTy)) { + uint64_t Index = Record[0]; + Constant *Val = ValueList.getConstantFwdRef(Record[1], + UnTy->getElementType(Index)); + V = ConstantUnion::get(UnTy, Val); } else if (const ArrayType *ATy = dyn_cast(CurTy)) { const Type *EltTy = ATy->getElementType(); for (unsigned i = 0; i != Size; ++i) Modified: llvm/trunk/lib/Bitcode/Writer/BitcodeWriter.cpp URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Bitcode/Writer/BitcodeWriter.cpp?rev=98680&r1=98679&r2=98680&view=diff ============================================================================== --- llvm/trunk/lib/Bitcode/Writer/BitcodeWriter.cpp (original) +++ llvm/trunk/lib/Bitcode/Writer/BitcodeWriter.cpp Tue Mar 16 16:25:55 2010 @@ -808,11 +808,25 @@ else if (isCStr7) AbbrevToUse = CString7Abbrev; } else if (isa(C) || isa(V) || - isa(C) || isa(V)) { + isa(V)) { Code = bitc::CST_CODE_AGGREGATE; for (unsigned i = 0, e = C->getNumOperands(); i != e; ++i) Record.push_back(VE.getValueID(C->getOperand(i))); AbbrevToUse = AggregateAbbrev; + } else if (isa(C)) { + Code = bitc::CST_CODE_AGGREGATE; + + // Unions only have one entry but we must send type along with it. + const Type *EntryKind = C->getOperand(0)->getType(); + + const UnionType *UnTy = cast(C->getType()); + int UnionIndex = UnTy->getElementTypeIndex(EntryKind); + assert(UnionIndex != -1 && "Constant union contains invalid entry"); + + Record.push_back(UnionIndex); + Record.push_back(VE.getValueID(C->getOperand(0))); + + AbbrevToUse = AggregateAbbrev; } else if (const ConstantExpr *CE = dyn_cast(C)) { switch (CE->getOpcode()) { default: Modified: llvm/trunk/lib/CodeGen/AsmPrinter/AsmPrinter.cpp URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/CodeGen/AsmPrinter/AsmPrinter.cpp?rev=98680&r1=98679&r2=98680&view=diff ============================================================================== --- llvm/trunk/lib/CodeGen/AsmPrinter/AsmPrinter.cpp (original) +++ llvm/trunk/lib/CodeGen/AsmPrinter/AsmPrinter.cpp Tue Mar 16 16:25:55 2010 @@ -1138,6 +1138,21 @@ "Layout of constant struct may be incorrect!"); } +static void EmitGlobalConstantUnion(const ConstantUnion *CU, + unsigned AddrSpace, AsmPrinter &AP) { + const TargetData *TD = AP.TM.getTargetData(); + unsigned Size = TD->getTypeAllocSize(CU->getType()); + + const Constant *Contents = CU->getOperand(0); + unsigned FilledSize = TD->getTypeAllocSize(Contents->getType()); + + // Print the actually filled part + AP.EmitGlobalConstant(Contents, AddrSpace); + + // And pad with enough zeroes + AP.OutStreamer.EmitZeros(Size-FilledSize, AddrSpace); +} + static void EmitGlobalConstantFP(const ConstantFP *CFP, unsigned AddrSpace, AsmPrinter &AP) { // FP Constants are printed as integer constants to avoid losing @@ -1257,9 +1272,6 @@ if (const ConstantFP *CFP = dyn_cast(CV)) return EmitGlobalConstantFP(CFP, AddrSpace, *this); - - if (const ConstantVector *V = dyn_cast(CV)) - return EmitGlobalConstantVector(V, AddrSpace, *this); if (isa(CV)) { unsigned Size = TM.getTargetData()->getTypeAllocSize(CV->getType()); @@ -1267,6 +1279,12 @@ return; } + if (const ConstantUnion *CVU = dyn_cast(CV)) + return EmitGlobalConstantUnion(CVU, AddrSpace, *this); + + if (const ConstantVector *V = dyn_cast(CV)) + return EmitGlobalConstantVector(V, AddrSpace, *this); + // Otherwise, it must be a ConstantExpr. Lower it to an MCExpr, then emit it // thread the streamer with EmitValue. OutStreamer.EmitValue(LowerConstant(CV, *this), Modified: llvm/trunk/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp?rev=98680&r1=98679&r2=98680&view=diff ============================================================================== --- llvm/trunk/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp (original) +++ llvm/trunk/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp Tue Mar 16 16:25:55 2010 @@ -2592,6 +2592,11 @@ } Ty = StTy->getElementType(Field); + } else if (const UnionType *UnTy = dyn_cast(Ty)) { + unsigned Field = cast(Idx)->getZExtValue(); + + // Offset canonically 0 for unions, but type changes + Ty = UnTy->getElementType(Field); } else { Ty = cast(Ty)->getElementType(); Modified: llvm/trunk/lib/Target/TargetData.cpp URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Target/TargetData.cpp?rev=98680&r1=98679&r2=98680&view=diff ============================================================================== --- llvm/trunk/lib/Target/TargetData.cpp (original) +++ llvm/trunk/lib/Target/TargetData.cpp Tue Mar 16 16:25:55 2010 @@ -460,6 +460,15 @@ case Type::StructTyID: // Get the layout annotation... which is lazily created on demand. return getStructLayout(cast(Ty))->getSizeInBits(); + case Type::UnionTyID: { + const UnionType *UnTy = cast(Ty); + uint64_t Size = 0; + for (UnionType::element_iterator i = UnTy->element_begin(), + e = UnTy->element_end(); i != e; ++i) { + Size = std::max(Size, getTypeSizeInBits(*i)); + } + return Size; + } case Type::IntegerTyID: return cast(Ty)->getBitWidth(); case Type::VoidTyID: @@ -516,6 +525,17 @@ unsigned Align = getAlignmentInfo(AGGREGATE_ALIGN, 0, abi_or_pref, Ty); return std::max(Align, (unsigned)Layout->getAlignment()); } + case Type::UnionTyID: { + const UnionType *UnTy = cast(Ty); + unsigned Align = 1; + + // Unions need the maximum alignment of all their entries + for (UnionType::element_iterator i = UnTy->element_begin(), + e = UnTy->element_end(); i != e; ++i) { + Align = std::max(Align, (unsigned)getAlignment(*i, abi_or_pref)); + } + return Align; + } case Type::IntegerTyID: case Type::VoidTyID: AlignType = INTEGER_ALIGN; @@ -600,6 +620,11 @@ // Update Ty to refer to current element Ty = STy->getElementType(FieldNo); + } else if (const UnionType *UnTy = dyn_cast(*TI)) { + unsigned FieldNo = cast(Indices[CurIDX])->getZExtValue(); + + // Offset into union is canonically 0, but type changes + Ty = UnTy->getElementType(FieldNo); } else { // Update Ty to refer to current element Ty = cast(Ty)->getElementType(); From bob.wilson at apple.com Tue Mar 16 16:44:40 2010 From: bob.wilson at apple.com (Bob Wilson) Date: Tue, 16 Mar 2010 21:44:40 -0000 Subject: [llvm-commits] [llvm] r98683 - in /llvm/trunk/lib/Target/ARM: ARMAddressingModes.h ARMBaseInstrInfo.cpp ARMISelDAGToDAG.cpp ARMInstrInfo.td ARMInstrNEON.td AsmPrinter/ARMAsmPrinter.cpp AsmPrinter/ARMInstPrinter.cpp NEONPreAllocPass.cpp Message-ID: <20100316214440.7A7392A6C12C@llvm.org> Author: bwilson Date: Tue Mar 16 16:44:40 2010 New Revision: 98683 URL: http://llvm.org/viewvc/llvm-project?rev=98683&view=rev Log: Remove redundant writeback flag from ARM address mode 6. Also remove the optional register update argument, which is currently unused -- when we add support for that, it can just be a separate operand. Modified: llvm/trunk/lib/Target/ARM/ARMAddressingModes.h llvm/trunk/lib/Target/ARM/ARMBaseInstrInfo.cpp llvm/trunk/lib/Target/ARM/ARMISelDAGToDAG.cpp llvm/trunk/lib/Target/ARM/ARMInstrInfo.td llvm/trunk/lib/Target/ARM/ARMInstrNEON.td llvm/trunk/lib/Target/ARM/AsmPrinter/ARMAsmPrinter.cpp llvm/trunk/lib/Target/ARM/AsmPrinter/ARMInstPrinter.cpp llvm/trunk/lib/Target/ARM/NEONPreAllocPass.cpp Modified: llvm/trunk/lib/Target/ARM/ARMAddressingModes.h URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Target/ARM/ARMAddressingModes.h?rev=98683&r1=98682&r2=98683&view=diff ============================================================================== --- llvm/trunk/lib/Target/ARM/ARMAddressingModes.h (original) +++ llvm/trunk/lib/Target/ARM/ARMAddressingModes.h Tue Mar 16 16:44:40 2010 @@ -520,23 +520,11 @@ // // This is used for NEON load / store instructions. // - // addrmode6 := reg with optional writeback and alignment + // addrmode6 := reg with optional alignment // - // This is stored in four operands [regaddr, regupdate, opc, align]. The - // first is the address register. The second register holds the value of - // a post-access increment for writeback or reg0 if no writeback or if the - // writeback increment is the size of the memory access. The third - // operand encodes whether there is writeback to the address register. The - // fourth operand is the value of the alignment specifier to use or zero if - // no explicit alignment. - - static inline unsigned getAM6Opc(bool WB = false) { - return (int)WB; - } - - static inline bool getAM6WBFlag(unsigned Mode) { - return Mode & 1; - } + // This is stored in two operands [regaddr, align]. The first is the + // address register. The second operand is the value of the alignment + // specifier to use or zero if no explicit alignment. } // end namespace ARM_AM } // end namespace llvm Modified: llvm/trunk/lib/Target/ARM/ARMBaseInstrInfo.cpp URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Target/ARM/ARMBaseInstrInfo.cpp?rev=98683&r1=98682&r2=98683&view=diff ============================================================================== --- llvm/trunk/lib/Target/ARM/ARMBaseInstrInfo.cpp (original) +++ llvm/trunk/lib/Target/ARM/ARMBaseInstrInfo.cpp Tue Mar 16 16:44:40 2010 @@ -727,10 +727,9 @@ assert((RC == ARM::QPRRegisterClass || RC == ARM::QPR_VFP2RegisterClass) && "Unknown regclass!"); // FIXME: Neon instructions should support predicates - if (Align >= 16 - && (getRegisterInfo().canRealignStack(MF))) { + if (Align >= 16 && (getRegisterInfo().canRealignStack(MF))) { AddDefaultPred(BuildMI(MBB, I, DL, get(ARM::VST1q64)) - .addFrameIndex(FI).addImm(0).addImm(0).addImm(128) + .addFrameIndex(FI).addImm(128) .addMemOperand(MMO) .addReg(SrcReg, getKillRegState(isKill))); } else { @@ -780,7 +779,7 @@ if (Align >= 16 && (getRegisterInfo().canRealignStack(MF))) { AddDefaultPred(BuildMI(MBB, I, DL, get(ARM::VLD1q64), DestReg) - .addFrameIndex(FI).addImm(0).addImm(0).addImm(128) + .addFrameIndex(FI).addImm(128) .addMemOperand(MMO)); } else { AddDefaultPred(BuildMI(MBB, I, DL, get(ARM::VLDRQ), DestReg) Modified: llvm/trunk/lib/Target/ARM/ARMISelDAGToDAG.cpp URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Target/ARM/ARMISelDAGToDAG.cpp?rev=98683&r1=98682&r2=98683&view=diff ============================================================================== --- llvm/trunk/lib/Target/ARM/ARMISelDAGToDAG.cpp (original) +++ llvm/trunk/lib/Target/ARM/ARMISelDAGToDAG.cpp Tue Mar 16 16:44:40 2010 @@ -80,8 +80,7 @@ SDValue &Mode); bool SelectAddrMode5(SDNode *Op, SDValue N, SDValue &Base, SDValue &Offset); - bool SelectAddrMode6(SDNode *Op, SDValue N, SDValue &Addr, SDValue &Update, - SDValue &Opc, SDValue &Align); + bool SelectAddrMode6(SDNode *Op, SDValue N, SDValue &Addr, SDValue &Align); bool SelectAddrModePC(SDNode *Op, SDValue N, SDValue &Offset, SDValue &Label); @@ -502,12 +501,8 @@ } bool ARMDAGToDAGISel::SelectAddrMode6(SDNode *Op, SDValue N, - SDValue &Addr, SDValue &Update, - SDValue &Opc, SDValue &Align) { + SDValue &Addr, SDValue &Align) { Addr = N; - // Default to no writeback. - Update = CurDAG->getRegister(0, MVT::i32); - Opc = CurDAG->getTargetConstant(ARM_AM::getAM6Opc(false), MVT::i32); // Default to no alignment. Align = CurDAG->getTargetConstant(0, MVT::i32); return true; @@ -1030,8 +1025,8 @@ assert(NumVecs >=2 && NumVecs <= 4 && "VLD NumVecs out-of-range"); DebugLoc dl = N->getDebugLoc(); - SDValue MemAddr, MemUpdate, MemOpc, Align; - if (!SelectAddrMode6(N, N->getOperand(2), MemAddr, MemUpdate, MemOpc, Align)) + SDValue MemAddr, Align; + if (!SelectAddrMode6(N, N->getOperand(2), MemAddr, Align)) return NULL; SDValue Chain = N->getOperand(0); @@ -1058,11 +1053,10 @@ SDValue PredReg = CurDAG->getRegister(0, MVT::i32); if (is64BitVector) { unsigned Opc = DOpcodes[OpcodeIndex]; - const SDValue Ops[] = { MemAddr, MemUpdate, MemOpc, Align, - Pred, PredReg, Chain }; + const SDValue Ops[] = { MemAddr, Align, Pred, PredReg, Chain }; std::vector ResTys(NumVecs, VT); ResTys.push_back(MVT::Other); - return CurDAG->getMachineNode(Opc, dl, ResTys, Ops, 7); + return CurDAG->getMachineNode(Opc, dl, ResTys, Ops, 5); } EVT RegVT = GetNEONSubregVT(VT); @@ -1070,11 +1064,10 @@ // Quad registers are directly supported for VLD2, // loading 2 pairs of D regs. unsigned Opc = QOpcodes0[OpcodeIndex]; - const SDValue Ops[] = { MemAddr, MemUpdate, MemOpc, Align, - Pred, PredReg, Chain }; + const SDValue Ops[] = { MemAddr, Align, Pred, PredReg, Chain }; std::vector ResTys(4, VT); ResTys.push_back(MVT::Other); - SDNode *VLd = CurDAG->getMachineNode(Opc, dl, ResTys, Ops, 7); + SDNode *VLd = CurDAG->getMachineNode(Opc, dl, ResTys, Ops, 5); Chain = SDValue(VLd, 4); // Combine the even and odd subregs to produce the result. @@ -1086,25 +1079,21 @@ // Otherwise, quad registers are loaded with two separate instructions, // where one loads the even registers and the other loads the odd registers. - // Enable writeback to the address register. - MemOpc = CurDAG->getTargetConstant(ARM_AM::getAM6Opc(true), MVT::i32); - std::vector ResTys(NumVecs, RegVT); ResTys.push_back(MemAddr.getValueType()); ResTys.push_back(MVT::Other); // Load the even subregs. unsigned Opc = QOpcodes0[OpcodeIndex]; - const SDValue OpsA[] = { MemAddr, MemUpdate, MemOpc, Align, - Pred, PredReg, Chain }; - SDNode *VLdA = CurDAG->getMachineNode(Opc, dl, ResTys, OpsA, 7); + const SDValue OpsA[] = { MemAddr, Align, Pred, PredReg, Chain }; + SDNode *VLdA = CurDAG->getMachineNode(Opc, dl, ResTys, OpsA, 5); Chain = SDValue(VLdA, NumVecs+1); // Load the odd subregs. Opc = QOpcodes1[OpcodeIndex]; - const SDValue OpsB[] = { SDValue(VLdA, NumVecs), MemUpdate, MemOpc, + const SDValue OpsB[] = { SDValue(VLdA, NumVecs), Align, Pred, PredReg, Chain }; - SDNode *VLdB = CurDAG->getMachineNode(Opc, dl, ResTys, OpsB, 7); + SDNode *VLdB = CurDAG->getMachineNode(Opc, dl, ResTys, OpsB, 5); Chain = SDValue(VLdB, NumVecs+1); // Combine the even and odd subregs to produce the result. @@ -1123,8 +1112,8 @@ assert(NumVecs >=2 && NumVecs <= 4 && "VST NumVecs out-of-range"); DebugLoc dl = N->getDebugLoc(); - SDValue MemAddr, MemUpdate, MemOpc, Align; - if (!SelectAddrMode6(N, N->getOperand(2), MemAddr, MemUpdate, MemOpc, Align)) + SDValue MemAddr, Align; + if (!SelectAddrMode6(N, N->getOperand(2), MemAddr, Align)) return NULL; SDValue Chain = N->getOperand(0); @@ -1150,10 +1139,8 @@ SDValue Pred = CurDAG->getTargetConstant(14, MVT::i32); SDValue PredReg = CurDAG->getRegister(0, MVT::i32); - SmallVector Ops; + SmallVector Ops; Ops.push_back(MemAddr); - Ops.push_back(MemUpdate); - Ops.push_back(MemOpc); Ops.push_back(Align); if (is64BitVector) { @@ -1163,7 +1150,7 @@ Ops.push_back(Pred); Ops.push_back(PredReg); Ops.push_back(Chain); - return CurDAG->getMachineNode(Opc, dl, MVT::Other, Ops.data(), NumVecs+7); + return CurDAG->getMachineNode(Opc, dl, MVT::Other, Ops.data(), NumVecs+5); } EVT RegVT = GetNEONSubregVT(VT); @@ -1180,15 +1167,12 @@ Ops.push_back(Pred); Ops.push_back(PredReg); Ops.push_back(Chain); - return CurDAG->getMachineNode(Opc, dl, MVT::Other, Ops.data(), 11); + return CurDAG->getMachineNode(Opc, dl, MVT::Other, Ops.data(), 9); } // Otherwise, quad registers are stored with two separate instructions, // where one stores the even registers and the other stores the odd registers. - // Enable writeback to the address register. - MemOpc = CurDAG->getTargetConstant(ARM_AM::getAM6Opc(true), MVT::i32); - // Store the even subregs. for (unsigned Vec = 0; Vec < NumVecs; ++Vec) Ops.push_back(CurDAG->getTargetExtractSubreg(ARM::DSUBREG_0, dl, RegVT, @@ -1198,20 +1182,20 @@ Ops.push_back(Chain); unsigned Opc = QOpcodes0[OpcodeIndex]; SDNode *VStA = CurDAG->getMachineNode(Opc, dl, MemAddr.getValueType(), - MVT::Other, Ops.data(), NumVecs+7); + MVT::Other, Ops.data(), NumVecs+5); Chain = SDValue(VStA, 1); // Store the odd subregs. Ops[0] = SDValue(VStA, 0); // MemAddr for (unsigned Vec = 0; Vec < NumVecs; ++Vec) - Ops[Vec+4] = CurDAG->getTargetExtractSubreg(ARM::DSUBREG_1, dl, RegVT, + Ops[Vec+2] = CurDAG->getTargetExtractSubreg(ARM::DSUBREG_1, dl, RegVT, N->getOperand(Vec+3)); - Ops[NumVecs+4] = Pred; - Ops[NumVecs+5] = PredReg; - Ops[NumVecs+6] = Chain; + Ops[NumVecs+2] = Pred; + Ops[NumVecs+3] = PredReg; + Ops[NumVecs+4] = Chain; Opc = QOpcodes1[OpcodeIndex]; SDNode *VStB = CurDAG->getMachineNode(Opc, dl, MemAddr.getValueType(), - MVT::Other, Ops.data(), NumVecs+7); + MVT::Other, Ops.data(), NumVecs+5); Chain = SDValue(VStB, 1); ReplaceUses(SDValue(N, 0), Chain); return NULL; @@ -1224,8 +1208,8 @@ assert(NumVecs >=2 && NumVecs <= 4 && "VLDSTLane NumVecs out-of-range"); DebugLoc dl = N->getDebugLoc(); - SDValue MemAddr, MemUpdate, MemOpc, Align; - if (!SelectAddrMode6(N, N->getOperand(2), MemAddr, MemUpdate, MemOpc, Align)) + SDValue MemAddr, Align; + if (!SelectAddrMode6(N, N->getOperand(2), MemAddr, Align)) return NULL; SDValue Chain = N->getOperand(0); @@ -1261,10 +1245,8 @@ SDValue Pred = CurDAG->getTargetConstant(14, MVT::i32); SDValue PredReg = CurDAG->getRegister(0, MVT::i32); - SmallVector Ops; + SmallVector Ops; Ops.push_back(MemAddr); - Ops.push_back(MemUpdate); - Ops.push_back(MemOpc); Ops.push_back(Align); unsigned Opc = 0; @@ -1291,12 +1273,12 @@ Ops.push_back(Chain); if (!IsLoad) - return CurDAG->getMachineNode(Opc, dl, MVT::Other, Ops.data(), NumVecs+8); + return CurDAG->getMachineNode(Opc, dl, MVT::Other, Ops.data(), NumVecs+6); std::vector ResTys(NumVecs, RegVT); ResTys.push_back(MVT::Other); SDNode *VLdLn = - CurDAG->getMachineNode(Opc, dl, ResTys, Ops.data(), NumVecs+8); + CurDAG->getMachineNode(Opc, dl, ResTys, Ops.data(), NumVecs+6); // For a 64-bit vector load to D registers, nothing more needs to be done. if (is64BitVector) return VLdLn; Modified: llvm/trunk/lib/Target/ARM/ARMInstrInfo.td URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Target/ARM/ARMInstrInfo.td?rev=98683&r1=98682&r2=98683&view=diff ============================================================================== --- llvm/trunk/lib/Target/ARM/ARMInstrInfo.td (original) +++ llvm/trunk/lib/Target/ARM/ARMInstrInfo.td Tue Mar 16 16:44:40 2010 @@ -392,9 +392,9 @@ // addrmode6 := reg with optional writeback // def addrmode6 : Operand, - ComplexPattern { + ComplexPattern { let PrintMethod = "printAddrMode6Operand"; - let MIOperandInfo = (ops GPR:$addr, GPR:$upd, i32imm, i32imm); + let MIOperandInfo = (ops GPR:$addr, i32imm); } // addrmodepc := pc + reg Modified: llvm/trunk/lib/Target/ARM/ARMInstrNEON.td URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Target/ARM/ARMInstrNEON.td?rev=98683&r1=98682&r2=98683&view=diff ============================================================================== --- llvm/trunk/lib/Target/ARM/ARMInstrNEON.td (original) +++ llvm/trunk/lib/Target/ARM/ARMInstrNEON.td Tue Mar 16 16:44:40 2010 @@ -227,7 +227,7 @@ class VLD3WB op7_4, string OpcodeStr, string Dt> : NLdSt<0,0b10,0b0101,op7_4, (outs DPR:$dst1, DPR:$dst2, DPR:$dst3, GPR:$wb), (ins addrmode6:$addr), IIC_VLD3, - OpcodeStr, Dt, "\\{$dst1, $dst2, $dst3\\}, $addr", + OpcodeStr, Dt, "\\{$dst1, $dst2, $dst3\\}, $addr!", "$addr.addr = $wb", []>; def VLD3d8 : VLD3D<0b0000, "vld3", "8">; @@ -259,7 +259,7 @@ : NLdSt<0,0b10,0b0001,op7_4, (outs DPR:$dst1, DPR:$dst2, DPR:$dst3, DPR:$dst4, GPR:$wb), (ins addrmode6:$addr), IIC_VLD4, - OpcodeStr, Dt, "\\{$dst1, $dst2, $dst3, $dst4\\}, $addr", + OpcodeStr, Dt, "\\{$dst1, $dst2, $dst3, $dst4\\}, $addr!", "$addr.addr = $wb", []>; def VLD4d8 : VLD4D<0b0000, "vld4", "8">; @@ -447,7 +447,7 @@ class VST3WB op7_4, string OpcodeStr, string Dt> : NLdSt<0,0b00,0b0101,op7_4, (outs GPR:$wb), (ins addrmode6:$addr, DPR:$src1, DPR:$src2, DPR:$src3), IIC_VST, - OpcodeStr, Dt, "\\{$src1, $src2, $src3\\}, $addr", + OpcodeStr, Dt, "\\{$src1, $src2, $src3\\}, $addr!", "$addr.addr = $wb", []>; def VST3d8 : VST3D<0b0000, "vst3", "8">; @@ -477,7 +477,7 @@ class VST4WB op7_4, string OpcodeStr, string Dt> : NLdSt<0,0b00,0b0001,op7_4, (outs GPR:$wb), (ins addrmode6:$addr, DPR:$src1, DPR:$src2, DPR:$src3, DPR:$src4), - IIC_VST, OpcodeStr, Dt, "\\{$src1, $src2, $src3, $src4\\}, $addr", + IIC_VST, OpcodeStr, Dt, "\\{$src1, $src2, $src3, $src4\\}, $addr!", "$addr.addr = $wb", []>; def VST4d8 : VST4D<0b0000, "vst4", "8">; Modified: llvm/trunk/lib/Target/ARM/AsmPrinter/ARMAsmPrinter.cpp URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Target/ARM/AsmPrinter/ARMAsmPrinter.cpp?rev=98683&r1=98682&r2=98683&view=diff ============================================================================== --- llvm/trunk/lib/Target/ARM/AsmPrinter/ARMAsmPrinter.cpp (original) +++ llvm/trunk/lib/Target/ARM/AsmPrinter/ARMAsmPrinter.cpp Tue Mar 16 16:44:40 2010 @@ -562,22 +562,13 @@ void ARMAsmPrinter::printAddrMode6Operand(const MachineInstr *MI, int Op) { const MachineOperand &MO1 = MI->getOperand(Op); const MachineOperand &MO2 = MI->getOperand(Op+1); - const MachineOperand &MO3 = MI->getOperand(Op+2); - const MachineOperand &MO4 = MI->getOperand(Op+3); O << "[" << getRegisterName(MO1.getReg()); - if (MO4.getImm()) { + if (MO2.getImm()) { // FIXME: Both darwin as and GNU as violate ARM docs here. - O << ", :" << MO4.getImm(); + O << ", :" << MO2.getImm(); } O << "]"; - - if (ARM_AM::getAM6WBFlag(MO3.getImm())) { - if (MO2.getReg() == 0) - O << "!"; - else - O << ", " << getRegisterName(MO2.getReg()); - } } void ARMAsmPrinter::printAddrModePCOperand(const MachineInstr *MI, int Op, Modified: llvm/trunk/lib/Target/ARM/AsmPrinter/ARMInstPrinter.cpp URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Target/ARM/AsmPrinter/ARMInstPrinter.cpp?rev=98683&r1=98682&r2=98683&view=diff ============================================================================== --- llvm/trunk/lib/Target/ARM/AsmPrinter/ARMInstPrinter.cpp (original) +++ llvm/trunk/lib/Target/ARM/AsmPrinter/ARMInstPrinter.cpp Tue Mar 16 16:44:40 2010 @@ -268,17 +268,13 @@ void ARMInstPrinter::printAddrMode6Operand(const MCInst *MI, unsigned OpNum) { const MCOperand &MO1 = MI->getOperand(OpNum); const MCOperand &MO2 = MI->getOperand(OpNum+1); - const MCOperand &MO3 = MI->getOperand(OpNum+2); - // FIXME: No support yet for specifying alignment. - O << '[' << getRegisterName(MO1.getReg()) << ']'; - - if (ARM_AM::getAM6WBFlag(MO3.getImm())) { - if (MO2.getReg() == 0) - O << '!'; - else - O << ", " << getRegisterName(MO2.getReg()); + O << "[" << getRegisterName(MO1.getReg()); + if (MO2.getImm()) { + // FIXME: Both darwin as and GNU as violate ARM docs here. + O << ", :" << MO2.getImm(); } + O << "]"; } void ARMInstPrinter::printAddrModePCOperand(const MCInst *MI, unsigned OpNum, Modified: llvm/trunk/lib/Target/ARM/NEONPreAllocPass.cpp URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Target/ARM/NEONPreAllocPass.cpp?rev=98683&r1=98682&r2=98683&view=diff ============================================================================== --- llvm/trunk/lib/Target/ARM/NEONPreAllocPass.cpp (original) +++ llvm/trunk/lib/Target/ARM/NEONPreAllocPass.cpp Tue Mar 16 16:44:40 2010 @@ -177,20 +177,20 @@ case ARM::VST2LNd8: case ARM::VST2LNd16: case ARM::VST2LNd32: - FirstOpnd = 4; + FirstOpnd = 2; NumRegs = 2; return true; case ARM::VST2q8: case ARM::VST2q16: case ARM::VST2q32: - FirstOpnd = 4; + FirstOpnd = 2; NumRegs = 4; return true; case ARM::VST2LNq16a: case ARM::VST2LNq32a: - FirstOpnd = 4; + FirstOpnd = 2; NumRegs = 2; Offset = 0; Stride = 2; @@ -198,7 +198,7 @@ case ARM::VST2LNq16b: case ARM::VST2LNq32b: - FirstOpnd = 4; + FirstOpnd = 2; NumRegs = 2; Offset = 1; Stride = 2; @@ -211,14 +211,14 @@ case ARM::VST3LNd8: case ARM::VST3LNd16: case ARM::VST3LNd32: - FirstOpnd = 4; + FirstOpnd = 2; NumRegs = 3; return true; case ARM::VST3q8a: case ARM::VST3q16a: case ARM::VST3q32a: - FirstOpnd = 5; + FirstOpnd = 3; NumRegs = 3; Offset = 0; Stride = 2; @@ -227,7 +227,7 @@ case ARM::VST3q8b: case ARM::VST3q16b: case ARM::VST3q32b: - FirstOpnd = 5; + FirstOpnd = 3; NumRegs = 3; Offset = 1; Stride = 2; @@ -235,7 +235,7 @@ case ARM::VST3LNq16a: case ARM::VST3LNq32a: - FirstOpnd = 4; + FirstOpnd = 2; NumRegs = 3; Offset = 0; Stride = 2; @@ -243,7 +243,7 @@ case ARM::VST3LNq16b: case ARM::VST3LNq32b: - FirstOpnd = 4; + FirstOpnd = 2; NumRegs = 3; Offset = 1; Stride = 2; @@ -256,14 +256,14 @@ case ARM::VST4LNd8: case ARM::VST4LNd16: case ARM::VST4LNd32: - FirstOpnd = 4; + FirstOpnd = 2; NumRegs = 4; return true; case ARM::VST4q8a: case ARM::VST4q16a: case ARM::VST4q32a: - FirstOpnd = 5; + FirstOpnd = 3; NumRegs = 4; Offset = 0; Stride = 2; @@ -272,7 +272,7 @@ case ARM::VST4q8b: case ARM::VST4q16b: case ARM::VST4q32b: - FirstOpnd = 5; + FirstOpnd = 3; NumRegs = 4; Offset = 1; Stride = 2; @@ -280,7 +280,7 @@ case ARM::VST4LNq16a: case ARM::VST4LNq32a: - FirstOpnd = 4; + FirstOpnd = 2; NumRegs = 4; Offset = 0; Stride = 2; @@ -288,7 +288,7 @@ case ARM::VST4LNq16b: case ARM::VST4LNq32b: - FirstOpnd = 4; + FirstOpnd = 2; NumRegs = 4; Offset = 1; Stride = 2; From evan.cheng at apple.com Tue Mar 16 16:51:27 2010 From: evan.cheng at apple.com (Evan Cheng) Date: Tue, 16 Mar 2010 21:51:27 -0000 Subject: [llvm-commits] [llvm] r98686 - in /llvm/trunk: lib/CodeGen/LiveIntervalAnalysis.cpp test/CodeGen/Generic/dbg_value.ll Message-ID: <20100316215127.9FFFC2A6C12C@llvm.org> Author: evancheng Date: Tue Mar 16 16:51:27 2010 New Revision: 98686 URL: http://llvm.org/viewvc/llvm-project?rev=98686&view=rev Log: Fix liveintervals handling of dbg_value instructions. Added: llvm/trunk/test/CodeGen/Generic/dbg_value.ll Modified: llvm/trunk/lib/CodeGen/LiveIntervalAnalysis.cpp Modified: llvm/trunk/lib/CodeGen/LiveIntervalAnalysis.cpp URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/CodeGen/LiveIntervalAnalysis.cpp?rev=98686&r1=98685&r2=98686&view=diff ============================================================================== --- llvm/trunk/lib/CodeGen/LiveIntervalAnalysis.cpp (original) +++ llvm/trunk/lib/CodeGen/LiveIntervalAnalysis.cpp Tue Mar 16 16:51:27 2010 @@ -141,7 +141,7 @@ for (MachineBasicBlock::iterator mii = mbbi->begin(), mie = mbbi->end(); mii != mie; ++mii) { if (mii->isDebugValue()) - OS << SlotIndex::getEmptyKey() << '\t' << *mii; + OS << " \t" << *mii; else OS << getInstructionIndex(mii) << '\t' << *mii; } @@ -583,6 +583,16 @@ // Look for kills, if it reaches a def before it's killed, then it shouldn't // be considered a livein. MachineBasicBlock::iterator mi = MBB->begin(); + MachineBasicBlock::iterator E = MBB->end(); + // Skip over DBG_VALUE at the start of the MBB. + if (mi != E && mi->isDebugValue()) { + while (++mi != E && mi->isDebugValue()) + ; + if (mi == E) + // MBB is empty except for DBG_VALUE's. + return; + } + SlotIndex baseIndex = MIIdx; SlotIndex start = baseIndex; if (getInstructionFromIndex(baseIndex) == 0) @@ -591,12 +601,7 @@ SlotIndex end = baseIndex; bool SeenDefUse = false; - MachineBasicBlock::iterator E = MBB->end(); while (mi != E) { - while (mi != E && mi->isDebugValue()) - ++mi; - if (mi == E) - break; if (mi->killsRegister(interval.reg, tri_)) { DEBUG(dbgs() << " killed"); end = baseIndex.getDefIndex(); @@ -613,10 +618,11 @@ break; } - ++mi; - if (mi != E && !mi->isDebugValue()) { + while (++mi != E && mi->isDebugValue()) + // Skip over DBG_VALUE. + ; + if (mi != E) baseIndex = indexes_->getNextNonNullIndex(baseIndex); - } } // Live-in register might not be used at all. Added: llvm/trunk/test/CodeGen/Generic/dbg_value.ll URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/CodeGen/Generic/dbg_value.ll?rev=98686&view=auto ============================================================================== --- llvm/trunk/test/CodeGen/Generic/dbg_value.ll (added) +++ llvm/trunk/test/CodeGen/Generic/dbg_value.ll Tue Mar 16 16:51:27 2010 @@ -0,0 +1,13 @@ +; RUN: llc < %s +; rdar://7759395 + +%0 = type { i32, i32 } + +define void @t(%0*, i32, i32, i32, i32) nounwind { + tail call void @llvm.dbg.value(metadata !{%0* %0}, i64 0, metadata !0) + unreachable +} + +declare void @llvm.dbg.value(metadata, i64, metadata) nounwind readnone + +!0 = metadata !{i32 0} ; From bob.wilson at apple.com Tue Mar 16 18:01:13 2010 From: bob.wilson at apple.com (Bob Wilson) Date: Tue, 16 Mar 2010 23:01:13 -0000 Subject: [llvm-commits] [llvm] r98692 - in /llvm/trunk/lib/Target/ARM: ARMAddressingModes.h ARMBaseInstrInfo.cpp ARMISelDAGToDAG.cpp ARMInstrInfo.td ARMInstrNEON.td AsmPrinter/ARMAsmPrinter.cpp AsmPrinter/ARMInstPrinter.cpp NEONPreAllocPass.cpp Message-ID: <20100316230113.944722A6C12C@llvm.org> Author: bwilson Date: Tue Mar 16 18:01:13 2010 New Revision: 98692 URL: http://llvm.org/viewvc/llvm-project?rev=98692&view=rev Log: Revert 98683. It is breaking something in the disassembler. Modified: llvm/trunk/lib/Target/ARM/ARMAddressingModes.h llvm/trunk/lib/Target/ARM/ARMBaseInstrInfo.cpp llvm/trunk/lib/Target/ARM/ARMISelDAGToDAG.cpp llvm/trunk/lib/Target/ARM/ARMInstrInfo.td llvm/trunk/lib/Target/ARM/ARMInstrNEON.td llvm/trunk/lib/Target/ARM/AsmPrinter/ARMAsmPrinter.cpp llvm/trunk/lib/Target/ARM/AsmPrinter/ARMInstPrinter.cpp llvm/trunk/lib/Target/ARM/NEONPreAllocPass.cpp Modified: llvm/trunk/lib/Target/ARM/ARMAddressingModes.h URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Target/ARM/ARMAddressingModes.h?rev=98692&r1=98691&r2=98692&view=diff ============================================================================== --- llvm/trunk/lib/Target/ARM/ARMAddressingModes.h (original) +++ llvm/trunk/lib/Target/ARM/ARMAddressingModes.h Tue Mar 16 18:01:13 2010 @@ -520,11 +520,23 @@ // // This is used for NEON load / store instructions. // - // addrmode6 := reg with optional alignment + // addrmode6 := reg with optional writeback and alignment // - // This is stored in two operands [regaddr, align]. The first is the - // address register. The second operand is the value of the alignment - // specifier to use or zero if no explicit alignment. + // This is stored in four operands [regaddr, regupdate, opc, align]. The + // first is the address register. The second register holds the value of + // a post-access increment for writeback or reg0 if no writeback or if the + // writeback increment is the size of the memory access. The third + // operand encodes whether there is writeback to the address register. The + // fourth operand is the value of the alignment specifier to use or zero if + // no explicit alignment. + + static inline unsigned getAM6Opc(bool WB = false) { + return (int)WB; + } + + static inline bool getAM6WBFlag(unsigned Mode) { + return Mode & 1; + } } // end namespace ARM_AM } // end namespace llvm Modified: llvm/trunk/lib/Target/ARM/ARMBaseInstrInfo.cpp URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Target/ARM/ARMBaseInstrInfo.cpp?rev=98692&r1=98691&r2=98692&view=diff ============================================================================== --- llvm/trunk/lib/Target/ARM/ARMBaseInstrInfo.cpp (original) +++ llvm/trunk/lib/Target/ARM/ARMBaseInstrInfo.cpp Tue Mar 16 18:01:13 2010 @@ -727,9 +727,10 @@ assert((RC == ARM::QPRRegisterClass || RC == ARM::QPR_VFP2RegisterClass) && "Unknown regclass!"); // FIXME: Neon instructions should support predicates - if (Align >= 16 && (getRegisterInfo().canRealignStack(MF))) { + if (Align >= 16 + && (getRegisterInfo().canRealignStack(MF))) { AddDefaultPred(BuildMI(MBB, I, DL, get(ARM::VST1q64)) - .addFrameIndex(FI).addImm(128) + .addFrameIndex(FI).addImm(0).addImm(0).addImm(128) .addMemOperand(MMO) .addReg(SrcReg, getKillRegState(isKill))); } else { @@ -779,7 +780,7 @@ if (Align >= 16 && (getRegisterInfo().canRealignStack(MF))) { AddDefaultPred(BuildMI(MBB, I, DL, get(ARM::VLD1q64), DestReg) - .addFrameIndex(FI).addImm(128) + .addFrameIndex(FI).addImm(0).addImm(0).addImm(128) .addMemOperand(MMO)); } else { AddDefaultPred(BuildMI(MBB, I, DL, get(ARM::VLDRQ), DestReg) Modified: llvm/trunk/lib/Target/ARM/ARMISelDAGToDAG.cpp URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Target/ARM/ARMISelDAGToDAG.cpp?rev=98692&r1=98691&r2=98692&view=diff ============================================================================== --- llvm/trunk/lib/Target/ARM/ARMISelDAGToDAG.cpp (original) +++ llvm/trunk/lib/Target/ARM/ARMISelDAGToDAG.cpp Tue Mar 16 18:01:13 2010 @@ -80,7 +80,8 @@ SDValue &Mode); bool SelectAddrMode5(SDNode *Op, SDValue N, SDValue &Base, SDValue &Offset); - bool SelectAddrMode6(SDNode *Op, SDValue N, SDValue &Addr, SDValue &Align); + bool SelectAddrMode6(SDNode *Op, SDValue N, SDValue &Addr, SDValue &Update, + SDValue &Opc, SDValue &Align); bool SelectAddrModePC(SDNode *Op, SDValue N, SDValue &Offset, SDValue &Label); @@ -501,8 +502,12 @@ } bool ARMDAGToDAGISel::SelectAddrMode6(SDNode *Op, SDValue N, - SDValue &Addr, SDValue &Align) { + SDValue &Addr, SDValue &Update, + SDValue &Opc, SDValue &Align) { Addr = N; + // Default to no writeback. + Update = CurDAG->getRegister(0, MVT::i32); + Opc = CurDAG->getTargetConstant(ARM_AM::getAM6Opc(false), MVT::i32); // Default to no alignment. Align = CurDAG->getTargetConstant(0, MVT::i32); return true; @@ -1025,8 +1030,8 @@ assert(NumVecs >=2 && NumVecs <= 4 && "VLD NumVecs out-of-range"); DebugLoc dl = N->getDebugLoc(); - SDValue MemAddr, Align; - if (!SelectAddrMode6(N, N->getOperand(2), MemAddr, Align)) + SDValue MemAddr, MemUpdate, MemOpc, Align; + if (!SelectAddrMode6(N, N->getOperand(2), MemAddr, MemUpdate, MemOpc, Align)) return NULL; SDValue Chain = N->getOperand(0); @@ -1053,10 +1058,11 @@ SDValue PredReg = CurDAG->getRegister(0, MVT::i32); if (is64BitVector) { unsigned Opc = DOpcodes[OpcodeIndex]; - const SDValue Ops[] = { MemAddr, Align, Pred, PredReg, Chain }; + const SDValue Ops[] = { MemAddr, MemUpdate, MemOpc, Align, + Pred, PredReg, Chain }; std::vector ResTys(NumVecs, VT); ResTys.push_back(MVT::Other); - return CurDAG->getMachineNode(Opc, dl, ResTys, Ops, 5); + return CurDAG->getMachineNode(Opc, dl, ResTys, Ops, 7); } EVT RegVT = GetNEONSubregVT(VT); @@ -1064,10 +1070,11 @@ // Quad registers are directly supported for VLD2, // loading 2 pairs of D regs. unsigned Opc = QOpcodes0[OpcodeIndex]; - const SDValue Ops[] = { MemAddr, Align, Pred, PredReg, Chain }; + const SDValue Ops[] = { MemAddr, MemUpdate, MemOpc, Align, + Pred, PredReg, Chain }; std::vector ResTys(4, VT); ResTys.push_back(MVT::Other); - SDNode *VLd = CurDAG->getMachineNode(Opc, dl, ResTys, Ops, 5); + SDNode *VLd = CurDAG->getMachineNode(Opc, dl, ResTys, Ops, 7); Chain = SDValue(VLd, 4); // Combine the even and odd subregs to produce the result. @@ -1079,21 +1086,25 @@ // Otherwise, quad registers are loaded with two separate instructions, // where one loads the even registers and the other loads the odd registers. + // Enable writeback to the address register. + MemOpc = CurDAG->getTargetConstant(ARM_AM::getAM6Opc(true), MVT::i32); + std::vector ResTys(NumVecs, RegVT); ResTys.push_back(MemAddr.getValueType()); ResTys.push_back(MVT::Other); // Load the even subregs. unsigned Opc = QOpcodes0[OpcodeIndex]; - const SDValue OpsA[] = { MemAddr, Align, Pred, PredReg, Chain }; - SDNode *VLdA = CurDAG->getMachineNode(Opc, dl, ResTys, OpsA, 5); + const SDValue OpsA[] = { MemAddr, MemUpdate, MemOpc, Align, + Pred, PredReg, Chain }; + SDNode *VLdA = CurDAG->getMachineNode(Opc, dl, ResTys, OpsA, 7); Chain = SDValue(VLdA, NumVecs+1); // Load the odd subregs. Opc = QOpcodes1[OpcodeIndex]; - const SDValue OpsB[] = { SDValue(VLdA, NumVecs), + const SDValue OpsB[] = { SDValue(VLdA, NumVecs), MemUpdate, MemOpc, Align, Pred, PredReg, Chain }; - SDNode *VLdB = CurDAG->getMachineNode(Opc, dl, ResTys, OpsB, 5); + SDNode *VLdB = CurDAG->getMachineNode(Opc, dl, ResTys, OpsB, 7); Chain = SDValue(VLdB, NumVecs+1); // Combine the even and odd subregs to produce the result. @@ -1112,8 +1123,8 @@ assert(NumVecs >=2 && NumVecs <= 4 && "VST NumVecs out-of-range"); DebugLoc dl = N->getDebugLoc(); - SDValue MemAddr, Align; - if (!SelectAddrMode6(N, N->getOperand(2), MemAddr, Align)) + SDValue MemAddr, MemUpdate, MemOpc, Align; + if (!SelectAddrMode6(N, N->getOperand(2), MemAddr, MemUpdate, MemOpc, Align)) return NULL; SDValue Chain = N->getOperand(0); @@ -1139,8 +1150,10 @@ SDValue Pred = CurDAG->getTargetConstant(14, MVT::i32); SDValue PredReg = CurDAG->getRegister(0, MVT::i32); - SmallVector Ops; + SmallVector Ops; Ops.push_back(MemAddr); + Ops.push_back(MemUpdate); + Ops.push_back(MemOpc); Ops.push_back(Align); if (is64BitVector) { @@ -1150,7 +1163,7 @@ Ops.push_back(Pred); Ops.push_back(PredReg); Ops.push_back(Chain); - return CurDAG->getMachineNode(Opc, dl, MVT::Other, Ops.data(), NumVecs+5); + return CurDAG->getMachineNode(Opc, dl, MVT::Other, Ops.data(), NumVecs+7); } EVT RegVT = GetNEONSubregVT(VT); @@ -1167,12 +1180,15 @@ Ops.push_back(Pred); Ops.push_back(PredReg); Ops.push_back(Chain); - return CurDAG->getMachineNode(Opc, dl, MVT::Other, Ops.data(), 9); + return CurDAG->getMachineNode(Opc, dl, MVT::Other, Ops.data(), 11); } // Otherwise, quad registers are stored with two separate instructions, // where one stores the even registers and the other stores the odd registers. + // Enable writeback to the address register. + MemOpc = CurDAG->getTargetConstant(ARM_AM::getAM6Opc(true), MVT::i32); + // Store the even subregs. for (unsigned Vec = 0; Vec < NumVecs; ++Vec) Ops.push_back(CurDAG->getTargetExtractSubreg(ARM::DSUBREG_0, dl, RegVT, @@ -1182,20 +1198,20 @@ Ops.push_back(Chain); unsigned Opc = QOpcodes0[OpcodeIndex]; SDNode *VStA = CurDAG->getMachineNode(Opc, dl, MemAddr.getValueType(), - MVT::Other, Ops.data(), NumVecs+5); + MVT::Other, Ops.data(), NumVecs+7); Chain = SDValue(VStA, 1); // Store the odd subregs. Ops[0] = SDValue(VStA, 0); // MemAddr for (unsigned Vec = 0; Vec < NumVecs; ++Vec) - Ops[Vec+2] = CurDAG->getTargetExtractSubreg(ARM::DSUBREG_1, dl, RegVT, + Ops[Vec+4] = CurDAG->getTargetExtractSubreg(ARM::DSUBREG_1, dl, RegVT, N->getOperand(Vec+3)); - Ops[NumVecs+2] = Pred; - Ops[NumVecs+3] = PredReg; - Ops[NumVecs+4] = Chain; + Ops[NumVecs+4] = Pred; + Ops[NumVecs+5] = PredReg; + Ops[NumVecs+6] = Chain; Opc = QOpcodes1[OpcodeIndex]; SDNode *VStB = CurDAG->getMachineNode(Opc, dl, MemAddr.getValueType(), - MVT::Other, Ops.data(), NumVecs+5); + MVT::Other, Ops.data(), NumVecs+7); Chain = SDValue(VStB, 1); ReplaceUses(SDValue(N, 0), Chain); return NULL; @@ -1208,8 +1224,8 @@ assert(NumVecs >=2 && NumVecs <= 4 && "VLDSTLane NumVecs out-of-range"); DebugLoc dl = N->getDebugLoc(); - SDValue MemAddr, Align; - if (!SelectAddrMode6(N, N->getOperand(2), MemAddr, Align)) + SDValue MemAddr, MemUpdate, MemOpc, Align; + if (!SelectAddrMode6(N, N->getOperand(2), MemAddr, MemUpdate, MemOpc, Align)) return NULL; SDValue Chain = N->getOperand(0); @@ -1245,8 +1261,10 @@ SDValue Pred = CurDAG->getTargetConstant(14, MVT::i32); SDValue PredReg = CurDAG->getRegister(0, MVT::i32); - SmallVector Ops; + SmallVector Ops; Ops.push_back(MemAddr); + Ops.push_back(MemUpdate); + Ops.push_back(MemOpc); Ops.push_back(Align); unsigned Opc = 0; @@ -1273,12 +1291,12 @@ Ops.push_back(Chain); if (!IsLoad) - return CurDAG->getMachineNode(Opc, dl, MVT::Other, Ops.data(), NumVecs+6); + return CurDAG->getMachineNode(Opc, dl, MVT::Other, Ops.data(), NumVecs+8); std::vector ResTys(NumVecs, RegVT); ResTys.push_back(MVT::Other); SDNode *VLdLn = - CurDAG->getMachineNode(Opc, dl, ResTys, Ops.data(), NumVecs+6); + CurDAG->getMachineNode(Opc, dl, ResTys, Ops.data(), NumVecs+8); // For a 64-bit vector load to D registers, nothing more needs to be done. if (is64BitVector) return VLdLn; Modified: llvm/trunk/lib/Target/ARM/ARMInstrInfo.td URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Target/ARM/ARMInstrInfo.td?rev=98692&r1=98691&r2=98692&view=diff ============================================================================== --- llvm/trunk/lib/Target/ARM/ARMInstrInfo.td (original) +++ llvm/trunk/lib/Target/ARM/ARMInstrInfo.td Tue Mar 16 18:01:13 2010 @@ -392,9 +392,9 @@ // addrmode6 := reg with optional writeback // def addrmode6 : Operand, - ComplexPattern { + ComplexPattern { let PrintMethod = "printAddrMode6Operand"; - let MIOperandInfo = (ops GPR:$addr, i32imm); + let MIOperandInfo = (ops GPR:$addr, GPR:$upd, i32imm, i32imm); } // addrmodepc := pc + reg Modified: llvm/trunk/lib/Target/ARM/ARMInstrNEON.td URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Target/ARM/ARMInstrNEON.td?rev=98692&r1=98691&r2=98692&view=diff ============================================================================== --- llvm/trunk/lib/Target/ARM/ARMInstrNEON.td (original) +++ llvm/trunk/lib/Target/ARM/ARMInstrNEON.td Tue Mar 16 18:01:13 2010 @@ -227,7 +227,7 @@ class VLD3WB op7_4, string OpcodeStr, string Dt> : NLdSt<0,0b10,0b0101,op7_4, (outs DPR:$dst1, DPR:$dst2, DPR:$dst3, GPR:$wb), (ins addrmode6:$addr), IIC_VLD3, - OpcodeStr, Dt, "\\{$dst1, $dst2, $dst3\\}, $addr!", + OpcodeStr, Dt, "\\{$dst1, $dst2, $dst3\\}, $addr", "$addr.addr = $wb", []>; def VLD3d8 : VLD3D<0b0000, "vld3", "8">; @@ -259,7 +259,7 @@ : NLdSt<0,0b10,0b0001,op7_4, (outs DPR:$dst1, DPR:$dst2, DPR:$dst3, DPR:$dst4, GPR:$wb), (ins addrmode6:$addr), IIC_VLD4, - OpcodeStr, Dt, "\\{$dst1, $dst2, $dst3, $dst4\\}, $addr!", + OpcodeStr, Dt, "\\{$dst1, $dst2, $dst3, $dst4\\}, $addr", "$addr.addr = $wb", []>; def VLD4d8 : VLD4D<0b0000, "vld4", "8">; @@ -447,7 +447,7 @@ class VST3WB op7_4, string OpcodeStr, string Dt> : NLdSt<0,0b00,0b0101,op7_4, (outs GPR:$wb), (ins addrmode6:$addr, DPR:$src1, DPR:$src2, DPR:$src3), IIC_VST, - OpcodeStr, Dt, "\\{$src1, $src2, $src3\\}, $addr!", + OpcodeStr, Dt, "\\{$src1, $src2, $src3\\}, $addr", "$addr.addr = $wb", []>; def VST3d8 : VST3D<0b0000, "vst3", "8">; @@ -477,7 +477,7 @@ class VST4WB op7_4, string OpcodeStr, string Dt> : NLdSt<0,0b00,0b0001,op7_4, (outs GPR:$wb), (ins addrmode6:$addr, DPR:$src1, DPR:$src2, DPR:$src3, DPR:$src4), - IIC_VST, OpcodeStr, Dt, "\\{$src1, $src2, $src3, $src4\\}, $addr!", + IIC_VST, OpcodeStr, Dt, "\\{$src1, $src2, $src3, $src4\\}, $addr", "$addr.addr = $wb", []>; def VST4d8 : VST4D<0b0000, "vst4", "8">; Modified: llvm/trunk/lib/Target/ARM/AsmPrinter/ARMAsmPrinter.cpp URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Target/ARM/AsmPrinter/ARMAsmPrinter.cpp?rev=98692&r1=98691&r2=98692&view=diff ============================================================================== --- llvm/trunk/lib/Target/ARM/AsmPrinter/ARMAsmPrinter.cpp (original) +++ llvm/trunk/lib/Target/ARM/AsmPrinter/ARMAsmPrinter.cpp Tue Mar 16 18:01:13 2010 @@ -562,13 +562,22 @@ void ARMAsmPrinter::printAddrMode6Operand(const MachineInstr *MI, int Op) { const MachineOperand &MO1 = MI->getOperand(Op); const MachineOperand &MO2 = MI->getOperand(Op+1); + const MachineOperand &MO3 = MI->getOperand(Op+2); + const MachineOperand &MO4 = MI->getOperand(Op+3); O << "[" << getRegisterName(MO1.getReg()); - if (MO2.getImm()) { + if (MO4.getImm()) { // FIXME: Both darwin as and GNU as violate ARM docs here. - O << ", :" << MO2.getImm(); + O << ", :" << MO4.getImm(); } O << "]"; + + if (ARM_AM::getAM6WBFlag(MO3.getImm())) { + if (MO2.getReg() == 0) + O << "!"; + else + O << ", " << getRegisterName(MO2.getReg()); + } } void ARMAsmPrinter::printAddrModePCOperand(const MachineInstr *MI, int Op, Modified: llvm/trunk/lib/Target/ARM/AsmPrinter/ARMInstPrinter.cpp URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Target/ARM/AsmPrinter/ARMInstPrinter.cpp?rev=98692&r1=98691&r2=98692&view=diff ============================================================================== --- llvm/trunk/lib/Target/ARM/AsmPrinter/ARMInstPrinter.cpp (original) +++ llvm/trunk/lib/Target/ARM/AsmPrinter/ARMInstPrinter.cpp Tue Mar 16 18:01:13 2010 @@ -268,13 +268,17 @@ void ARMInstPrinter::printAddrMode6Operand(const MCInst *MI, unsigned OpNum) { const MCOperand &MO1 = MI->getOperand(OpNum); const MCOperand &MO2 = MI->getOperand(OpNum+1); + const MCOperand &MO3 = MI->getOperand(OpNum+2); - O << "[" << getRegisterName(MO1.getReg()); - if (MO2.getImm()) { - // FIXME: Both darwin as and GNU as violate ARM docs here. - O << ", :" << MO2.getImm(); + // FIXME: No support yet for specifying alignment. + O << '[' << getRegisterName(MO1.getReg()) << ']'; + + if (ARM_AM::getAM6WBFlag(MO3.getImm())) { + if (MO2.getReg() == 0) + O << '!'; + else + O << ", " << getRegisterName(MO2.getReg()); } - O << "]"; } void ARMInstPrinter::printAddrModePCOperand(const MCInst *MI, unsigned OpNum, Modified: llvm/trunk/lib/Target/ARM/NEONPreAllocPass.cpp URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Target/ARM/NEONPreAllocPass.cpp?rev=98692&r1=98691&r2=98692&view=diff ============================================================================== --- llvm/trunk/lib/Target/ARM/NEONPreAllocPass.cpp (original) +++ llvm/trunk/lib/Target/ARM/NEONPreAllocPass.cpp Tue Mar 16 18:01:13 2010 @@ -177,20 +177,20 @@ case ARM::VST2LNd8: case ARM::VST2LNd16: case ARM::VST2LNd32: - FirstOpnd = 2; + FirstOpnd = 4; NumRegs = 2; return true; case ARM::VST2q8: case ARM::VST2q16: case ARM::VST2q32: - FirstOpnd = 2; + FirstOpnd = 4; NumRegs = 4; return true; case ARM::VST2LNq16a: case ARM::VST2LNq32a: - FirstOpnd = 2; + FirstOpnd = 4; NumRegs = 2; Offset = 0; Stride = 2; @@ -198,7 +198,7 @@ case ARM::VST2LNq16b: case ARM::VST2LNq32b: - FirstOpnd = 2; + FirstOpnd = 4; NumRegs = 2; Offset = 1; Stride = 2; @@ -211,14 +211,14 @@ case ARM::VST3LNd8: case ARM::VST3LNd16: case ARM::VST3LNd32: - FirstOpnd = 2; + FirstOpnd = 4; NumRegs = 3; return true; case ARM::VST3q8a: case ARM::VST3q16a: case ARM::VST3q32a: - FirstOpnd = 3; + FirstOpnd = 5; NumRegs = 3; Offset = 0; Stride = 2; @@ -227,7 +227,7 @@ case ARM::VST3q8b: case ARM::VST3q16b: case ARM::VST3q32b: - FirstOpnd = 3; + FirstOpnd = 5; NumRegs = 3; Offset = 1; Stride = 2; @@ -235,7 +235,7 @@ case ARM::VST3LNq16a: case ARM::VST3LNq32a: - FirstOpnd = 2; + FirstOpnd = 4; NumRegs = 3; Offset = 0; Stride = 2; @@ -243,7 +243,7 @@ case ARM::VST3LNq16b: case ARM::VST3LNq32b: - FirstOpnd = 2; + FirstOpnd = 4; NumRegs = 3; Offset = 1; Stride = 2; @@ -256,14 +256,14 @@ case ARM::VST4LNd8: case ARM::VST4LNd16: case ARM::VST4LNd32: - FirstOpnd = 2; + FirstOpnd = 4; NumRegs = 4; return true; case ARM::VST4q8a: case ARM::VST4q16a: case ARM::VST4q32a: - FirstOpnd = 3; + FirstOpnd = 5; NumRegs = 4; Offset = 0; Stride = 2; @@ -272,7 +272,7 @@ case ARM::VST4q8b: case ARM::VST4q16b: case ARM::VST4q32b: - FirstOpnd = 3; + FirstOpnd = 5; NumRegs = 4; Offset = 1; Stride = 2; @@ -280,7 +280,7 @@ case ARM::VST4LNq16a: case ARM::VST4LNq32a: - FirstOpnd = 2; + FirstOpnd = 4; NumRegs = 4; Offset = 0; Stride = 2; @@ -288,7 +288,7 @@ case ARM::VST4LNq16b: case ARM::VST4LNq32b: - FirstOpnd = 2; + FirstOpnd = 4; NumRegs = 4; Offset = 1; Stride = 2; From bob.wilson at apple.com Tue Mar 16 18:40:32 2010 From: bob.wilson at apple.com (Bob Wilson) Date: Tue, 16 Mar 2010 23:40:32 -0000 Subject: [llvm-commits] [llvm] r98694 - /llvm/trunk/lib/CodeGen/BranchFolding.cpp Message-ID: <20100316234032.D6B082A6C12C@llvm.org> Author: bwilson Date: Tue Mar 16 18:40:32 2010 New Revision: 98694 URL: http://llvm.org/viewvc/llvm-project?rev=98694&view=rev Log: Remove a check that can no longer be true, after r84803. Modified: llvm/trunk/lib/CodeGen/BranchFolding.cpp Modified: llvm/trunk/lib/CodeGen/BranchFolding.cpp URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/CodeGen/BranchFolding.cpp?rev=98694&r1=98693&r2=98694&view=diff ============================================================================== --- llvm/trunk/lib/CodeGen/BranchFolding.cpp (original) +++ llvm/trunk/lib/CodeGen/BranchFolding.cpp Tue Mar 16 18:40:32 2010 @@ -1143,22 +1143,6 @@ !IsBetterFallthrough(PriorTBB, MBB)) DoTransform = false; - // We don't want to do this transformation if we have control flow like: - // br cond BB2 - // BB1: - // .. - // jmp BBX - // BB2: - // .. - // ret - // - // In this case, we could actually be moving the return block *into* a - // loop! - if (DoTransform && !MBB->succ_empty() && - (!PriorTBB->canFallThrough() || PriorTBB->empty())) - DoTransform = false; - - if (DoTransform) { // Reverse the branch so we will fall through on the previous true cond. SmallVector NewPriorCond(PriorCond); From andrewl at lenharth.org Tue Mar 16 19:59:36 2010 From: andrewl at lenharth.org (Andrew Lenharth) Date: Wed, 17 Mar 2010 00:59:36 -0000 Subject: [llvm-commits] [poolalloc] r98699 - /poolalloc/trunk/include/dsa/sv/set.h Message-ID: <20100317005936.64FEE2A6C12C@llvm.org> Author: alenhar2 Date: Tue Mar 16 19:59:36 2010 New Revision: 98699 URL: http://llvm.org/viewvc/llvm-project?rev=98699&view=rev Log: avoid uninitialized access Modified: poolalloc/trunk/include/dsa/sv/set.h Modified: poolalloc/trunk/include/dsa/sv/set.h URL: http://llvm.org/viewvc/llvm-project/poolalloc/trunk/include/dsa/sv/set.h?rev=98699&r1=98698&r2=98699&view=diff ============================================================================== --- poolalloc/trunk/include/dsa/sv/set.h (original) +++ poolalloc/trunk/include/dsa/sv/set.h Tue Mar 16 19:59:36 2010 @@ -171,13 +171,13 @@ const_iterator find(const key_type& k) const { const_iterator i = std::lower_bound(container_.begin(), container_.end(), k); - if (*i == k) return i; + if (i != container_.end() && *i == k) return i; return container_.end(); } iterator find(const key_type& k) { iterator i = std::lower_bound(container_.begin(), container_.end(), k); - if (*i == k) return i; + if (i != container_.end() && *i == k) return i; return container_.end(); } From andrewl at lenharth.org Tue Mar 16 20:00:46 2010 From: andrewl at lenharth.org (Andrew Lenharth) Date: Wed, 17 Mar 2010 01:00:46 -0000 Subject: [llvm-commits] [poolalloc] r98700 - in /poolalloc/trunk: include/dsa/DSCallGraph.h include/dsa/DSGraph.h include/dsa/DSNode.h include/dsa/DataStructure.h lib/DSA/BottomUpClosure.cpp lib/DSA/CompleteBottomUp.cpp lib/DSA/DSGraph.cpp lib/DSA/DataStructure.cpp lib/DSA/Local.cpp lib/DSA/Printer.cpp lib/DSA/TopDownClosure.cpp lib/PoolAllocate/RunTimeAssociate.cpp lib/PoolAllocate/TransformFunctionBody.cpp Message-ID: <20100317010046.6B2F52A6C12C@llvm.org> Author: alenhar2 Date: Tue Mar 16 20:00:46 2010 New Revision: 98700 URL: http://llvm.org/viewvc/llvm-project?rev=98700&view=rev Log: Precompute SCCs and callgraphs inline everything in the precomputed SCC todo: don't remove unresolved callsites Modified: poolalloc/trunk/include/dsa/DSCallGraph.h poolalloc/trunk/include/dsa/DSGraph.h poolalloc/trunk/include/dsa/DSNode.h poolalloc/trunk/include/dsa/DataStructure.h poolalloc/trunk/lib/DSA/BottomUpClosure.cpp poolalloc/trunk/lib/DSA/CompleteBottomUp.cpp poolalloc/trunk/lib/DSA/DSGraph.cpp poolalloc/trunk/lib/DSA/DataStructure.cpp poolalloc/trunk/lib/DSA/Local.cpp poolalloc/trunk/lib/DSA/Printer.cpp poolalloc/trunk/lib/DSA/TopDownClosure.cpp poolalloc/trunk/lib/PoolAllocate/RunTimeAssociate.cpp poolalloc/trunk/lib/PoolAllocate/TransformFunctionBody.cpp Modified: poolalloc/trunk/include/dsa/DSCallGraph.h URL: http://llvm.org/viewvc/llvm-project/poolalloc/trunk/include/dsa/DSCallGraph.h?rev=98700&r1=98699&r2=98700&view=diff ============================================================================== --- poolalloc/trunk/include/dsa/DSCallGraph.h (original) +++ poolalloc/trunk/include/dsa/DSCallGraph.h Tue Mar 16 20:00:46 2010 @@ -17,15 +17,15 @@ #include "dsa/sv/set.h" #include +#include "llvm/Function.h" +#include "llvm/DerivedTypes.h" #include "llvm/Support/CallSite.h" - -namespace llvm { -class Function; -} +#include "llvm/Support/FormattedStream.h" template class KeyIterator { Iter I; + public: typedef typename Iter::difference_type difference_type; typedef typename Iter::value_type::first_type value_type; @@ -33,58 +33,151 @@ typedef typename Iter::value_type::first_type& reference; typedef typename Iter::iterator_category iterator_category; - KeyIterator(Iter i) :I(i) {} - Iter base() const { return I; } - reference operator*() const { return I->first; } - KeyIterator operator+(difference_type n) const { return KeyIterator(I + n); } - KeyIterator& operator++() { ++I; return *this; } - KeyIterator operator++(int) { Iter OI = I; ++I; return KeyIterator(OI); } - KeyIterator& operator+= (difference_type n) { I += n; return *this; } - KeyIterator operator- (difference_type n) const { return KeyIterator(I - n); } - KeyIterator& operator--() { --I; return *this; } - KeyIterator operator--(int) { Iter OI = I; --I; return KeyIterator(OI); } - KeyIterator& operator-=(difference_type n) { I -= n; return *this; } - pointer operator->() const { return &I->first; } - bool operator==(const KeyIterator& RHS) const { return I == RHS.I; } - bool operator!=(const KeyIterator& RHS) const { return I != RHS.I; } + KeyIterator(Iter i) : I(i) { } + + Iter base() const { + return I; + } + + reference operator*() const { + return I->first; + } + + KeyIterator operator+(difference_type n) const { + return KeyIterator(I + n); + } + + KeyIterator & operator++() { + ++I; + return *this; + } + + KeyIterator operator++(int) { + Iter OI = I; + ++I; + return KeyIterator(OI); + } + + KeyIterator & operator+=(difference_type n) { + I += n; + return *this; + } + + KeyIterator operator-(difference_type n) const { + return KeyIterator(I - n); + } + + KeyIterator & operator--() { + --I; + return *this; + } + + KeyIterator operator--(int) { + Iter OI = I; + --I; + return KeyIterator(OI); + } + + KeyIterator & operator-=(difference_type n) { + I -= n; + return *this; + } + + pointer operator->() const { + return &I->first; + } + + bool operator==(const KeyIterator& RHS) const { + return I == RHS.I; + } + + bool operator!=(const KeyIterator& RHS) const { + return I != RHS.I; + } }; class DSCallGraph { - +public: typedef sv::set FuncSet; typedef std::map ActualCalleesTy; + typedef std::map SimpleCalleesTy; +private: ActualCalleesTy ActualCallees; + SimpleCalleesTy SimpleCallees; + + FuncSet EmptyActual; + FuncSet EmptySimple; public: - typedef ActualCalleesTy::mapped_type::const_iterator iterator; + DSCallGraph() {} + + typedef ActualCalleesTy::mapped_type::const_iterator callee_iterator; typedef KeyIterator key_iterator; + typedef SimpleCalleesTy::mapped_type::const_iterator flat_iterator; + typedef KeyIterator flat_key_iterator; void insert(llvm::CallSite CS, const llvm::Function* F) { - if (F) ActualCallees[CS].insert(F); + if (F) { + ActualCallees[CS].insert(F); + SimpleCallees[CS.getInstruction()->getParent()->getParent()].insert(F); + //Create an empty set for the callee, hence all called functions get to be + // in the call graph also. This simplifies SCC formation + SimpleCallees[F]; + } } template void insert(llvm::CallSite CS, Iterator _begin, Iterator _end) { - for(; _begin != _end; ++_begin) + for (; _begin != _end; ++_begin) insert(CS, *_begin); } - iterator callee_begin(llvm::CallSite CS) const { + callee_iterator callee_begin(llvm::CallSite CS) const { ActualCalleesTy::const_iterator ii = ActualCallees.find(CS); if (ii == ActualCallees.end()) - ii = ActualCallees.find(llvm::CallSite()); + return EmptyActual.end(); return ii->second.begin(); } - iterator callee_end(llvm::CallSite CS) const { + callee_iterator callee_end(llvm::CallSite CS) const { ActualCalleesTy::const_iterator ii = ActualCallees.find(CS); if (ii == ActualCallees.end()) - ii = ActualCallees.find(llvm::CallSite()); + return EmptyActual.end(); return ii->second.end(); } + key_iterator key_begin() const { + return key_iterator(ActualCallees.begin()); + } + + key_iterator key_end() const { + return key_iterator(ActualCallees.end()); + } + + flat_iterator flat_callee_begin(const llvm::Function* F) const { + SimpleCalleesTy::const_iterator ii = SimpleCallees.find(F); + if (ii == SimpleCallees.end()) + return EmptySimple.end(); + return ii->second.begin(); + } + + flat_iterator flat_callee_end(const llvm::Function* F) const { + SimpleCalleesTy::const_iterator ii = SimpleCallees.find(F); + if (ii == SimpleCallees.end()) + return EmptySimple.end(); + return ii->second.end(); + } + + flat_key_iterator flat_key_begin() const { + return flat_key_iterator(SimpleCallees.begin()); + } + + flat_key_iterator flat_key_end() const { + return flat_key_iterator(SimpleCallees.end()); + } + unsigned callee_size(llvm::CallSite CS) const { ActualCalleesTy::const_iterator ii = ActualCallees.find(CS); @@ -105,12 +198,191 @@ ActualCallees.clear(); } - key_iterator key_begin() const { - return key_iterator(ActualCallees.begin()); +}; + +class DSSCCGraph { +public: + //SCCs, each element is an SCC + std::map SCCs; + //mapping of functions in SCCs to SCCs index + std::map invmap; + + unsigned nextSCC; + + //Functions we know about that aren't called + sv::set knownRoots; + + std::map > SCCCallees; + std::map > ExtCallees; + + DSCallGraph oldGraph; + +private: + typedef std::map TFMap; + typedef std::vector TFStack; + + bool hasPointers(const llvm::Function* F) { + if (F->isVarArg()) return true; + if (F->getReturnType()->isPointerTy()) return true; + for (llvm::Function::const_arg_iterator ii = F->arg_begin(), ee = F->arg_end(); + ii != ee; ++ii) + if (ii->getType()->isPointerTy()) return true; + return false; } - key_iterator key_end() const { - return key_iterator(ActualCallees.end()); + unsigned tarjan_rec(const llvm::Function* F, TFStack& Stack, unsigned &NextID, + TFMap& ValMap, DSCallGraph& cg) { + assert(!ValMap.count(F) && "Shouldn't revisit functions!"); + unsigned Min = NextID++, MyID = Min; + ValMap[F] = Min; + Stack.push_back(F); + + // The edges out of the current node are the call site targets... + for (DSCallGraph::flat_iterator ii = cg.flat_callee_begin(F), + ee = cg.flat_callee_end(F); ii != ee; ++ii) { + if (hasPointers(*ii) && !(*ii)->isDeclaration()) { + unsigned M = Min; + // Have we visited the destination function yet? + TFMap::iterator It = ValMap.find(*ii); + if (It == ValMap.end()) // No, visit it now. + M = tarjan_rec(*ii, Stack, NextID, ValMap, cg); + else if (std::find(Stack.begin(), Stack.end(), *ii) != Stack.end()) + M = It->second; + if (M < Min) Min = M; + } + } + + assert(ValMap[F] == MyID && "SCC construction assumption wrong!"); + if (Min != MyID) + return Min; // This is part of a larger SCC! + + // If this is a new SCC, process it now. + ++nextSCC; + + const llvm::Function* NF = 0; + do { + NF = Stack.back(); + Stack.pop_back(); + assert(NF && "Null Function"); + assert(invmap.find(NF) == invmap.end() && "Function already in invmap"); + invmap[NF] = nextSCC; + assert(SCCs[nextSCC].find(NF) == SCCs[nextSCC].end() && + "Function already in SCC"); + SCCs[nextSCC].insert(NF); + } while (NF != F); + + return MyID; + } + + void buildSCC(DSCallGraph& DSG) { + TFStack Stack; + TFMap ValMap; + unsigned NextID = 1; + + for (DSCallGraph::flat_key_iterator ii = DSG.flat_key_begin(), + ee = DSG.flat_key_end(); ii != ee; ++ii) + if (!ValMap.count(*ii)) + tarjan_rec(*ii, Stack, NextID, ValMap, DSG); + } + + void buildCallGraph(DSCallGraph& DSG) { + for(DSCallGraph::flat_key_iterator ii = DSG.flat_key_begin(), + ee = DSG.flat_key_end(); ii != ee; ++ii) { + assert (*ii && "Null Function"); + assert(invmap.find(*ii) != invmap.end() && "Unknown Function"); + for (DSCallGraph::flat_iterator fi = DSG.flat_callee_begin(*ii), + fe = DSG.flat_callee_end(*ii); fi != fe; ++fi) { + assert(*fi && "Null Function"); + assert(invmap.find(*fi) != invmap.end() && "Unknown Function"); + if (invmap[*ii] != invmap[*fi]) // No self calls + if (hasPointers(*fi)) { + if ((*fi)->isDeclaration()) + ExtCallees[invmap[*ii]].insert(invmap[*fi]); + else + SCCCallees[invmap[*ii]].insert(invmap[*fi]); + } + } + } + } + + void buildRoots() { + sv::set knownCallees; + sv::set knownCallers; + for (std::map >::iterator + ii = SCCCallees.begin(), ee = SCCCallees.end(); ii != ee; ++ii) { + knownCallees.insert(ii->second.begin(), ii->second.end()); + knownCallers.insert(ii->first); + } + for (sv::set::iterator ii = knownCallers.begin(), + ee = knownCallers.end(); ii != ee; ++ii) + if (!knownCallees.count(*ii)) + knownRoots.insert(*ii); + } + + void assertMapValid() { + for (std::map::iterator ii = SCCs.begin(), + ee = SCCs.end(); ii != ee; ++ii) { + for (DSCallGraph::FuncSet::iterator i = ii->second.begin(), + e = ii->second.end(); i != e; ++i) { + assert(*i && "Null Function in map"); + assert(invmap.find(*i) != invmap.end() && "Function not in invmap"); + assert(invmap[*i] == ii->first && "invmap doesn't match map"); + } + } + + for (std::map::iterator ii = invmap.begin(), + ee = invmap.end(); ii != ee; ++ii) { + assert(ii->first && "Null Function in invmap"); + assert(SCCs.find(ii->second) != SCCs.end() && "Function in invmap but not in map"); + assert(SCCs[ii->second].count(ii->first) && "SCC doesn't contain function"); + } + } + +public: + + DSSCCGraph(DSCallGraph& DSG) :nextSCC(0) { + oldGraph = DSG; + + buildSCC(DSG); + assertMapValid(); + + buildCallGraph(DSG); + + buildRoots(); + + } + + void dump() { + //function map + for (std::map::iterator ii = SCCs.begin(), + ee = SCCs.end(); ii != ee; ++ii) { + llvm::errs() << "Functions in " << ii->first << ":"; + for (DSCallGraph::FuncSet::iterator i = ii->second.begin(), + e = ii->second.end(); i != e; ++i) + llvm::errs() << " " << *i << "(" << invmap[*i] << ")"; + llvm::errs() << "\n"; + } + +// for (std::map::iterator ii = invmap.begin(), +// ee = invmap.end(); ii != ee; ++ii) +// llvm::errs() << ii->first << " -> " << ii->second << "\n"; + + //SCC map + for (std::map >::iterator ii = SCCCallees.begin(), + ee = SCCCallees.end(); ii != ee; ++ii) { + llvm::errs() << "CallGraph[" << ii->first << "]"; + for (sv::set::iterator i = ii->second.begin(), + e = ii->second.end(); i != e; ++i) + llvm::errs() << " " << *i; + llvm::errs() << "\n"; + } + + //Functions we know about that aren't called + llvm::errs() << "Roots:"; + for (sv::set::iterator ii = knownRoots.begin(), + ee = knownRoots.end(); ii != ee; ++ii) + llvm::errs() << " " << *ii; + llvm::errs() << "\n"; } }; Modified: poolalloc/trunk/include/dsa/DSGraph.h URL: http://llvm.org/viewvc/llvm-project/poolalloc/trunk/include/dsa/DSGraph.h?rev=98700&r1=98699&r2=98700&view=diff ============================================================================== --- poolalloc/trunk/include/dsa/DSGraph.h (original) +++ poolalloc/trunk/include/dsa/DSGraph.h Tue Mar 16 20:00:46 2010 @@ -16,6 +16,7 @@ #define LLVM_ANALYSIS_DSGRAPH_H #include "dsa/DSNode.h" +#include "dsa/DSCallGraph.h" #include "llvm/ADT/EquivalenceClasses.h" #include @@ -42,7 +43,7 @@ typedef std::map ValueMapTy; ValueMapTy ValueMap; - typedef sv::set GlobalSetTy; + typedef std::set GlobalSetTy; GlobalSetTy GlobalSet; EquivalenceClasses &GlobalECs; @@ -68,6 +69,7 @@ iterator find(const Value *V) { + assert(V); iterator I = ValueMap.find(V); if (I != ValueMap.end()) return I; @@ -81,6 +83,7 @@ return I; } const_iterator find(const Value *V) const { + assert(V); const_iterator I = ValueMap.find(V); if (I != ValueMap.end()) return I; @@ -135,6 +138,7 @@ /// operator[] - Return the DSNodeHandle for the specified value, creating a /// new null handle if there is no entry yet. DSNodeHandle &operator[](const Value *V) { + assert(V); iterator I = ValueMap.find(V); if (I != ValueMap.end()) return I->second; // Return value if already exists. @@ -327,6 +331,7 @@ // addAuxFunctionCall - Add a call site to the AuxFunctionCallList void addAuxFunctionCall(DSCallSite D) { AuxFunctionCalls.push_front(D); } + void buildCallGraph(DSCallGraph& DCG) const; /// removeFunction - Specify that all call sites to the function have been /// fully specified by a pass such as StdLibPass. Modified: poolalloc/trunk/include/dsa/DSNode.h URL: http://llvm.org/viewvc/llvm-project/poolalloc/trunk/include/dsa/DSNode.h?rev=98700&r1=98699&r2=98700&view=diff ============================================================================== --- poolalloc/trunk/include/dsa/DSNode.h (original) +++ poolalloc/trunk/include/dsa/DSNode.h Tue Mar 16 20:00:46 2010 @@ -130,15 +130,7 @@ /// links are just going to be clobbered anyway. /// DSNode(const DSNode &, DSGraph *G, bool NullLinks = false); - -#if 0 - ~DSNode() { - dropAllReferences(); - assert(hasNoReferrers() && "Referrers to dead node exist!"); - } -#else ~DSNode(); -#endif // Iterator for graph interface... Defined in DSGraphTraits.h typedef DSNodeIterator iterator; Modified: poolalloc/trunk/include/dsa/DataStructure.h URL: http://llvm.org/viewvc/llvm-project/poolalloc/trunk/include/dsa/DataStructure.h?rev=98700&r1=98699&r2=98700&view=diff ============================================================================== --- poolalloc/trunk/include/dsa/DataStructure.h (original) +++ poolalloc/trunk/include/dsa/DataStructure.h Tue Mar 16 20:00:46 2010 @@ -235,13 +235,11 @@ bool runOnModuleInternal(Module &M); private: - void calculateGraph(DSGraph* G); - - unsigned calculateGraphs(const Function *F, - std::vector &Stack, - unsigned &NextID, - std::map &ValMap); - + void mergeSCCs(DSSCCGraph& DSG); + + DSGraph* postOrder(DSSCCGraph& DSG, unsigned scc, sv::set& marked); + + void calculateGraph(DSGraph* G, DSSCCGraph& DSG); void CloneAuxIntoGlobal(DSGraph* G); void cloneGlobalsInto(DSGraph* G); Modified: poolalloc/trunk/lib/DSA/BottomUpClosure.cpp URL: http://llvm.org/viewvc/llvm-project/poolalloc/trunk/lib/DSA/BottomUpClosure.cpp?rev=98700&r1=98699&r2=98700&view=diff ============================================================================== --- poolalloc/trunk/lib/DSA/BottomUpClosure.cpp (original) +++ poolalloc/trunk/lib/DSA/BottomUpClosure.cpp Tue Mar 16 20:00:46 2010 @@ -28,6 +28,7 @@ STATISTIC (MaxSCC, "Maximum SCC Size in Call Graph"); STATISTIC (NumInlines, "Number of graphs inlined"); STATISTIC (NumCallEdges, "Number of 'actual' call edges"); + STATISTIC (NumSCCMerges, "Number of SCC merges"); RegisterPass X("dsa-bu", "Bottom-up Data Structure Analysis"); @@ -51,8 +52,41 @@ // inline bottum up // // We must split these out (they were merged in PLDI07) to handle multiple -// entry-points correctly. +// entry-points correctly. As a bonus, we can be more aggressive at propagating +// information upwards, as long as we don't remove unresolved call sites. bool BUDataStructures::runOnModuleInternal(Module& M) { + //Find SCCs and make SCC call graph + DSSCCGraph DSG(callgraph); + + errs() << "DSNode: " << sizeof(DSNode) << "\nDSCallSite: " + << sizeof(DSCallSite) << "\n"; + +// DSG.dump(); + + //merge SCCs + mergeSCCs(DSG); + + //Post order traversal: + { + //errs() << *DSG.knownRoots.begin() << " -> " << *DSG.knownRoots.rbegin() << "\n"; + sv::set marked; + for (sv::set::const_iterator ii = DSG.knownRoots.begin(), + ee = DSG.knownRoots.end(); ii != ee; ++ii) { + //errs() << *ii << " "; + DSGraph* G = postOrder(DSG, *ii, marked); + CloneAuxIntoGlobal(G); + } + } + + + return false; + + std::vector EntryPoints; + EP = &getAnalysis(); + EP->findEntryPoints(M, EntryPoints); + + #if 0 + std::vector Stack; std::map ValMap; unsigned NextID = 1; @@ -84,6 +118,7 @@ } errs() << "done unreachable Funcs\n"; + #endif // If we computed any temporary indcallgraphs, free them now. for (std::map, @@ -129,6 +164,51 @@ return false; } +void BUDataStructures::mergeSCCs(DSSCCGraph& DSG) { + + for (std::map::iterator ii = DSG.SCCs.begin(), + ee = DSG.SCCs.end(); ii != ee; ++ii) { + + DSGraph* SCCGraph = 0; + unsigned SCCSize = 0; + for (DSCallGraph::FuncSet::iterator Fi = ii->second.begin(), + Fe = ii->second.end(); Fi != Fe; ++Fi) { + const Function* F = *Fi; + if (F->isDeclaration()) continue; + ++SCCSize; + DSGraph* NFG = getOrCreateGraph(F); + if (!SCCGraph) { + SCCGraph = NFG; + } + if (NFG != SCCGraph) { + ++NumSCCMerges; + // Update the Function -> DSG map. + for (DSGraph::retnodes_iterator I = NFG->retnodes_begin(), + E = NFG->retnodes_end(); I != E; ++I) + setDSGraph(*I->first, SCCGraph); + + SCCGraph->spliceFrom(NFG); + delete NFG; + } + } + if (MaxSCC < SCCSize) MaxSCC = SCCSize; + } +} + +DSGraph* BUDataStructures::postOrder(DSSCCGraph& DSG, unsigned scc, + sv::set& marked) { + DSGraph* G = getDSGraph(**DSG.SCCs[scc].begin()); + if (marked.count(scc)) return G; + + for(sv::set::iterator ii = DSG.SCCCallees[scc].begin(), + ee = DSG.SCCCallees[scc].end(); ii != ee; ++ii) + postOrder(DSG, *ii, marked); + + marked.insert(scc); + calculateGraph(G, DSG); + return G; +} + void BUDataStructures::finalizeGlobals(void) { // Any unresolved call can be removed (resolved) if it does not contain // external functions and it is not reachable from any call that does @@ -157,169 +237,6 @@ GlobalsGraph->getScalarMap().clear_scalars(); } -static void GetAllCallees(const DSCallSite &CS, - std::vector &Callees) { - if (CS.isDirectCall()) { - if (!CS.getCalleeFunc()->isDeclaration()) - Callees.push_back(CS.getCalleeFunc()); - } else if (!CS.getCalleeNode()->isIncompleteNode()) { - // Get all callees. - if (!CS.getCalleeNode()->isExternFuncNode()) - CS.getCalleeNode()->addFullFunctionList(Callees); - } -} - -static void GetAnyCallees(const DSCallSite &CS, - std::vector &Callees) { - if (CS.isDirectCall()) { - if (!CS.getCalleeFunc()->isDeclaration()) - Callees.push_back(CS.getCalleeFunc()); - } else { - // Get any callees. - unsigned OldSize = Callees.size(); - CS.getCalleeNode()->addFullFunctionList(Callees); - - // If any of the callees are unresolvable, remove them - for (unsigned i = OldSize; i != Callees.size();) - if (Callees[i]->isDeclaration()) { - Callees.erase(Callees.begin() + i); - } else - ++i; - } -} - -/// GetAllAuxCallees - Return a list containing all of the resolvable callees in -/// the aux list for the specified graph in the Callees vector. -static void GetAllAuxCallees(DSGraph* G, std::vector &Callees) { - Callees.clear(); - for (DSGraph::afc_iterator I = G->afc_begin(), E = G->afc_end(); I != E; ++I) - GetAllCallees(*I, Callees); -} - -unsigned BUDataStructures::calculateGraphs(const Function *F, - std::vector &Stack, - unsigned &NextID, - std::map &ValMap) { - assert(!ValMap.count(F) && "Shouldn't revisit functions!"); - unsigned Min = NextID++, MyID = Min; - ValMap[F] = Min; - Stack.push_back(F); - - // FIXME! This test should be generalized to be any function that we have - // already processed, in the case when there isn't a main or there are - // unreachable functions! - if (F->isDeclaration()) { // sprintf, fprintf, sscanf, etc... - // No callees! - Stack.pop_back(); - ValMap[F] = ~0; - return Min; - } - - DSGraph* Graph = getOrCreateGraph(F); - - // Find all callee functions. - std::vector CalleeFunctions; - GetAllAuxCallees(Graph, CalleeFunctions); - - // The edges out of the current node are the call site targets... - for (unsigned i = 0, e = CalleeFunctions.size(); i != e; ++i) { - const Function *Callee = CalleeFunctions[i]; - unsigned M; - // Have we visited the destination function yet? - std::map::iterator It = ValMap.find(Callee); - if (It == ValMap.end()) // No, visit it now. - M = calculateGraphs(Callee, Stack, NextID, ValMap); - else // Yes, get it's number. - M = It->second; - if (M < Min) Min = M; - } - - assert(ValMap[F] == MyID && "SCC construction assumption wrong!"); - if (Min != MyID) - return Min; // This is part of a larger SCC! - - // If this is a new SCC, process it now. - if (Stack.back() == F) { // Special case the single "SCC" case here. - DEBUG(errs() << "Visiting single node SCC #: " << MyID << " fn: " - << F->getName() << "\n"); - Stack.pop_back(); - DEBUG(errs() << " [BU] Calculating graph for: " << F->getName()<< "\n"); - calculateGraph(Graph); - DEBUG(errs() << " [BU] Done inlining: " << F->getName() << " [" - << Graph->getGraphSize() << "+" << Graph->getAuxFunctionCalls().size() - << "]\n"); - - if (MaxSCC < 1) MaxSCC = 1; - - // Should we revisit the graph? Only do it if there are now new resolvable - // callees - GetAllAuxCallees(Graph, CalleeFunctions); - if (!CalleeFunctions.empty()) { - DEBUG(errs() << "Recalculating " << F->getName() << " due to new knowledge\n"); - ValMap.erase(F); - return calculateGraphs(F, Stack, NextID, ValMap); - } else { - ValMap[F] = ~0U; - } - return MyID; - - } else { - // SCCFunctions - Keep track of the functions in the current SCC - // - std::vector SCCGraphs; - - unsigned SCCSize = 1; - const Function *NF = Stack.back(); - ValMap[NF] = ~0U; - DSGraph* SCCGraph = getDSGraph(*NF); - - // First thing first, collapse all of the DSGraphs into a single graph for - // the entire SCC. Splice all of the graphs into one and discard all of the - // old graphs. - // - while (NF != F) { - Stack.pop_back(); - NF = Stack.back(); - ValMap[NF] = ~0U; - - DSGraph* NFG = getDSGraph(*NF); - - if (NFG != SCCGraph) { - // Update the Function -> DSG map. - for (DSGraph::retnodes_iterator I = NFG->retnodes_begin(), - E = NFG->retnodes_end(); I != E; ++I) - setDSGraph(*I->first, SCCGraph); - - SCCGraph->spliceFrom(NFG); - delete NFG; - ++SCCSize; - } - } - Stack.pop_back(); - - DEBUG(errs() << "Calculating graph for SCC #: " << MyID << " of size: " - << SCCSize << "\n"); - - // Compute the Max SCC Size. - if (MaxSCC < SCCSize) - MaxSCC = SCCSize; - - // Clean up the graph before we start inlining a bunch again... - SCCGraph->removeDeadNodes(DSGraph::KeepUnreachableGlobals); - - // Now that we have one big happy family, resolve all of the call sites in - // the graph... - calculateGraph(SCCGraph); - DEBUG(errs() << " [BU] Done inlining SCC [" << SCCGraph->getGraphSize() - << "+" << SCCGraph->getAuxFunctionCalls().size() << "]\n" - << "DONE with SCC #: " << MyID << "\n"); - - // We never have to revisit "SCC" processed functions... - return MyID; - } - - return MyID; // == Min -} void BUDataStructures::CloneAuxIntoGlobal(DSGraph* G) { DSGraph* GG = G->getGlobalsGraph(); @@ -345,7 +262,7 @@ } } -void BUDataStructures::calculateGraph(DSGraph* Graph) { +void BUDataStructures::calculateGraph(DSGraph* Graph, DSSCCGraph& DSG) { DEBUG(Graph->AssertGraphOK(); Graph->getGlobalsGraph()->AssertGraphOK()); // If this graph contains the main function, clone the globals graph into this @@ -384,33 +301,29 @@ // Fast path for noop calls. Note that we don't care about merging globals // in the callee with nodes in the caller here. if (CS.getRetVal().isNull() && CS.getNumPtrArgs() == 0) { - if (!CS.isDirectCall()) { - GetAnyCallees(CS, CalledFuncs); - callgraph.insert(CS.getCallSite(), CalledFuncs.begin(), CalledFuncs.end()); - } TempFCs.erase(TempFCs.begin()); continue; } - GetAllCallees(CS, CalledFuncs); + std::copy(DSG.oldGraph.callee_begin(CS.getCallSite()), + DSG.oldGraph.callee_end(CS.getCallSite()), + std::back_inserter(CalledFuncs)); + + std::vector::iterator ErasePoint = + std::remove_if(CalledFuncs.begin(), CalledFuncs.end(), + std::mem_fun(&Function::isDeclaration)); + CalledFuncs.erase(ErasePoint, CalledFuncs.end()); if (CalledFuncs.empty()) { - //Get any callees we do have for the callgraph - if (!CS.isDirectCall()) { - GetAnyCallees(CS, CalledFuncs); - callgraph.insert(CS.getCallSite(), CalledFuncs.begin(), CalledFuncs.end()); - } // Remember that we could not resolve this yet! AuxCallsList.splice(AuxCallsList.end(), TempFCs, TempFCs.begin()); continue; } DSGraph *GI; - - callgraph.insert(CS.getCallSite(), CalledFuncs.begin(), CalledFuncs.end()); - if (CalledFuncs.size() == 1) { - const Function *Callee = CalledFuncs[0]; + for (unsigned x = 0; x < CalledFuncs.size(); ++x) { + const Function *Callee = CalledFuncs[x]; // Get the data structure graph for the called function. GI = getDSGraph(*Callee); // Graph to inline @@ -424,85 +337,7 @@ DSGraph::StripAllocaBit|DSGraph::DontCloneCallNodes); ++NumInlines; DEBUG(Graph->AssertGraphOK();); - } else { - bool doDebug = false; - DEBUG(doDebug = true); - if (doDebug) { - errs() << "In Fns: " << Graph->getFunctionNames() << "\n"; - errs() << " calls " << CalledFuncs.size() - << " fns from site: " << CS.getCallSite().getInstruction() - << " " << *CS.getCallSite().getInstruction(); - errs() << " Fns ="; - unsigned NumPrinted = 0; - - for (std::vector::iterator I = CalledFuncs.begin(), - E = CalledFuncs.end(); I != E; ++I) - if (NumPrinted++ < 8) { - errs() << " " << (*I)->getName(); - } - errs() << "\n"; - } - - // See if we already computed a graph for this set of callees. - std::sort(CalledFuncs.begin(), CalledFuncs.end()); - std::pair > &IndCallGraph = - IndCallGraphMap[CalledFuncs]; - - if (IndCallGraph.first == 0) { - std::vector::iterator I = CalledFuncs.begin(), - E = CalledFuncs.end(); - - // Start with a copy of the first graph. - GI = IndCallGraph.first = new DSGraph(getDSGraph(**I), GlobalECs, *TypeSS); - GI->setGlobalsGraph(Graph->getGlobalsGraph()); - std::vector &Args = IndCallGraph.second; - - // Get the argument nodes for the first callee. The return value is - // the 0th index in the vector. - GI->getFunctionArgumentsForCall(*I, Args); - - // Merge all of the other callees into this graph. - for (++I; I != E; ++I) { - // If the graph already contains the nodes for the function, don't - // bother merging it in again. - if (!GI->containsFunction(*I)) { - GI->cloneInto(getDSGraph(**I)); - ++NumInlines; - } - - std::vector NextArgs; - GI->getFunctionArgumentsForCall(*I, NextArgs); - unsigned i = 0, e = Args.size(); - for (; i != e; ++i) { - if (i == NextArgs.size()) break; - Args[i].mergeWith(NextArgs[i]); - } - for (e = NextArgs.size(); i != e; ++i) - Args.push_back(NextArgs[i]); - } - - // Clean up the final graph! - GI->removeDeadNodes(DSGraph::KeepUnreachableGlobals); - } else { - DEBUG(errs() << "***\n*** RECYCLED GRAPH ***\n***\n"); - } - - GI = IndCallGraph.first; - - // Merge the unified graph into this graph now. - DEBUG(errs() << " Inlining multi callee graph " - << "[" << GI->getGraphSize() << "+" - << GI->getAuxFunctionCalls().size() << "] into '" - << Graph->getFunctionNames() << "' [" << Graph->getGraphSize() << "+" - << Graph->getAuxFunctionCalls().size() << "]\n"); - - Graph->mergeInGraph(CS, IndCallGraph.second, *GI, - DSGraph::StripAllocaBit | - DSGraph::DontCloneCallNodes); - ++NumInlines; } - DEBUG(Graph->AssertGraphOK();); - DEBUG(Graph->getGlobalsGraph()->AssertGraphOK()); TempFCs.erase(TempFCs.begin()); } Modified: poolalloc/trunk/lib/DSA/CompleteBottomUp.cpp URL: http://llvm.org/viewvc/llvm-project/poolalloc/trunk/lib/DSA/CompleteBottomUp.cpp?rev=98700&r1=98699&r2=98700&view=diff ============================================================================== --- poolalloc/trunk/lib/DSA/CompleteBottomUp.cpp (original) +++ poolalloc/trunk/lib/DSA/CompleteBottomUp.cpp Tue Mar 16 20:00:46 2010 @@ -51,7 +51,7 @@ //mege nodes in the global graph for these functions for (DSCallGraph::key_iterator ii = callgraph.key_begin(), ee = callgraph.key_end(); ii != ee; ++ii) { - DSCallGraph::iterator csi = callgraph.callee_begin(*ii), + DSCallGraph::callee_iterator csi = callgraph.callee_begin(*ii), cse = callgraph.callee_end(*ii); if (csi != cse && SM.find(*csi) != SM.end()) { DSNodeHandle& SrcNH = SM.find(*csi)->second; Modified: poolalloc/trunk/lib/DSA/DSGraph.cpp URL: http://llvm.org/viewvc/llvm-project/poolalloc/trunk/lib/DSA/DSGraph.cpp?rev=98700&r1=98699&r2=98700&view=diff ============================================================================== --- poolalloc/trunk/lib/DSA/DSGraph.cpp (original) +++ poolalloc/trunk/lib/DSA/DSGraph.cpp Tue Mar 16 20:00:46 2010 @@ -38,10 +38,20 @@ #define COLLAPSE_ARRAYS_AGGRESSIVELY 0 namespace { - STATISTIC (NumCallNodesMerged, "Number of call nodes merged"); - STATISTIC (NumDNE , "Number of nodes removed by reachability"); - STATISTIC (NumTrivialDNE , "Number of nodes trivially removed"); + STATISTIC (NumCallNodesMerged , "Number of call nodes merged"); + STATISTIC (NumDNE , "Number of nodes removed by reachability"); + STATISTIC (NumTrivialDNE , "Number of nodes trivially removed"); STATISTIC (NumTrivialGlobalDNE, "Number of globals trivially removed"); + STATISTIC (NumFiltered , "Number of calls filtered"); + static cl::opt noDSACallConv("dsa-no-filter-callcc", + cl::desc("Don't filter call sites based on calling convention."), + cl::Hidden); + static cl::opt noDSACallVA("dsa-no-filter-vararg", + cl::desc("Don't filter call sites based on vararg presense"), + cl::Hidden); + static cl::opt noDSACallFP("dsa-no-filter-intfp", + cl::desc("Don't filter call sites based on implicit integer to fp conversion"), + cl::Hidden); } /// getFunctionNames - Return a space separated list of the name of the @@ -1215,4 +1225,53 @@ } } +// Filter potential call targets +static bool functionIsCallable(CallSite CS, const Function* F) { + //Which targets do we choose? + //Conservative: all of them + //Pretty Safe: same calling convention, otherwise undefined behavior + //Safe on some archs: + //Safe?: vararg call only calling vararg functions + //Safe?: non-vararg call only calling non-vararg functions + //Safe?: iany/ptr can't be interchanged in args w/ float/double + //Not so safe: number of args matching + const PointerType* PT = cast(CS.getCalledValue()->getType()); + const FunctionType* FT = cast(PT->getElementType()); + + if (!noDSACallConv && CS.getCallingConv() != F->getCallingConv()) return false; + if (!noDSACallVA && FT->isVarArg() != F->isVarArg()) return false; + if (!noDSACallFP) { + FunctionType::param_iterator Pi = FT->param_begin(), Pe = FT->param_end(), + Ai = F->getFunctionType()->param_begin(), + Ae = F->getFunctionType()->param_end(); + while (Ai != Ae && Pi != Pe) { + if ((Ai->get()->isFPOrFPVectorTy() && !Pi->get()->isFPOrFPVectorTy()) + || + (!Ai->get()->isFPOrFPVectorTy() && Pi->get()->isFPOrFPVectorTy())) + return false; + ++Ai; + ++Pi; + } + } + //F can be called from CS; + return true; +} +void DSGraph::buildCallGraph(DSCallGraph& DCG) const { + const std::list& Calls = getAuxFunctionCalls(); + for (std::list::const_iterator ii = Calls.begin(), ee = Calls.end(); + ii != ee; ++ii) + if (ii->isDirectCall()) { + DCG.insert(ii->getCallSite(), ii->getCalleeFunc()); + } else { + CallSite CS = ii->getCallSite(); + std::vector MaybeTargets; + ii->getCalleeNode()->addFullFunctionList(MaybeTargets); + for (std::vector::iterator Fi = MaybeTargets.begin(), + Fe = MaybeTargets.end(); Fi != Fe; ++Fi) + if (functionIsCallable(CS, *Fi)) + DCG.insert(CS, *Fi); + else + ++NumFiltered; + } +} Modified: poolalloc/trunk/lib/DSA/DataStructure.cpp URL: http://llvm.org/viewvc/llvm-project/poolalloc/trunk/lib/DSA/DataStructure.cpp?rev=98700&r1=98699&r2=98700&view=diff ============================================================================== --- poolalloc/trunk/lib/DSA/DataStructure.cpp (original) +++ poolalloc/trunk/lib/DSA/DataStructure.cpp Tue Mar 16 20:00:46 2010 @@ -85,6 +85,7 @@ //===----------------------------------------------------------------------===// DSNodeHandle &DSScalarMap::AddGlobal(const GlobalValue *GV) { + assert(GV); assert(ValueMap.count(GV) == 0 && "GV already exists!"); // If the node doesn't exist, check to see if it's a global that is @@ -179,8 +180,9 @@ DSNodeHandle ToNH(To,Offset); //Move the Links - for (unsigned x = 0, xe = Links.size(); x != xe; ++x) - if (!Links[x].isNull()) { + for (LinkMapTy::iterator ii = Links.begin(), ee = Links.end(); + ii != ee; ++ii) { + if (!ii->second.isNull()) { // Compute the offset into the current node at which to // merge this link. In the common case, this is a linear // relation to the offset in the original node (with @@ -189,9 +191,10 @@ // links at offset zero. unsigned MergeOffset = 0; if (ToNH.getNode()->getSize() != 1) - MergeOffset = (x + Offset) % ToNH.getNode()->getSize(); - ToNH.getNode()->addEdgeTo(MergeOffset, Links[x]); + MergeOffset = (ii->first + Offset) % ToNH.getNode()->getSize(); + ToNH.getNode()->addEdgeTo(MergeOffset, ii->second); } + } Links.clear(); // Remove this node from the parent graph's Nodes list. @@ -452,6 +455,8 @@ CurNodeH.getNode()->growSize(NH.getNode()->getSize() + NOffset); assert(!CurNodeH.getNode()->isDeadNode()); + + // Merge the NodeType information. CurNodeH.getNode()->NodeType |= N->NodeType; @@ -459,6 +464,27 @@ N->forwardNode(CurNodeH.getNode(), NOffset); assert(!CurNodeH.getNode()->isDeadNode()); + // Make all of the outgoing links of N now be outgoing links of CurNodeH. + // + for (LinkMapTy::iterator ii = N->Links.begin(), ee = N->Links.end(); + ii != ee; ++ii) + if (ii->second.getNode()) { + // Compute the offset into the current node at which to + // merge this link. In the common case, this is a linear + // relation to the offset in the original node (with + // wrapping), but if the current node gets collapsed due to + // recursive merging, we must make sure to merge in all remaining + // links at offset zero. + unsigned MergeOffset = 0; + DSNode *CN = CurNodeH.getNode(); + if (CN->Size != 1) + MergeOffset = (ii->first + NOffset) % CN->getSize(); + CN->addEdgeTo(MergeOffset, ii->second); + } + + // Now that there are no outgoing edges, all of the Links are dead. + N->Links.clear(); + // Merge the globals list... CurNodeH.getNode()->mergeGlobals(*N); Modified: poolalloc/trunk/lib/DSA/Local.cpp URL: http://llvm.org/viewvc/llvm-project/poolalloc/trunk/lib/DSA/Local.cpp?rev=98700&r1=98699&r2=98700&view=diff ============================================================================== --- poolalloc/trunk/lib/DSA/Local.cpp (original) +++ poolalloc/trunk/lib/DSA/Local.cpp Tue Mar 16 20:00:46 2010 @@ -522,8 +522,13 @@ Offset += (unsigned)TD.getStructLayout(STy)->getElementOffset(FieldNo); } else if (isa(*I)) { if (!isa(I.getOperand()) || - !cast(I.getOperand())->isNullValue()) + !cast(I.getOperand())->isNullValue()) { Value.getNode()->setArrayMarker(); + Value.getNode()->foldNodeCompletely(); + Value.getNode(); + Offset = 0; + break; + } } @@ -945,6 +950,7 @@ G->getAuxFunctionCalls() = G->getFunctionCalls(); setDSGraph(*I, G); propagateUnknownFlag(G); + G->buildCallGraph(callgraph); } Modified: poolalloc/trunk/lib/DSA/Printer.cpp URL: http://llvm.org/viewvc/llvm-project/poolalloc/trunk/lib/DSA/Printer.cpp?rev=98700&r1=98699&r2=98700&view=diff ============================================================================== --- poolalloc/trunk/lib/DSA/Printer.cpp (original) +++ poolalloc/trunk/lib/DSA/Printer.cpp Tue Mar 16 20:00:46 2010 @@ -365,15 +365,14 @@ void DataStructures::dumpCallGraph() const { - for (DSCallGraph::key_iterator ki = callgraph.key_begin(), - ke = callgraph.key_end(); ki != ke; ++ki) - if (*ki != CallSite()) { - errs() << ki->getInstruction()->getParent()->getParent()->getName() << ": ["; - for (DSCallGraph::iterator cbi = callgraph.callee_begin(*ki), - cbe = callgraph.callee_end(*ki); cbi != cbe; ++cbi) - errs() << (*cbi)->getName() << " "; - errs() << "]\n"; - } + for (DSCallGraph::flat_key_iterator ki = callgraph.flat_key_begin(), + ke = callgraph.flat_key_end(); ki != ke; ++ki) { + errs() << (*ki)->getName() << ": ["; + for (DSCallGraph::flat_iterator cbi = callgraph.flat_callee_begin(*ki), + cbe = callgraph.flat_callee_end(*ki); cbi != cbe; ++cbi) + errs() << (*cbi)->getName() << " "; + errs() << "]\n"; + } } // print - Print out the analysis results... Modified: poolalloc/trunk/lib/DSA/TopDownClosure.cpp URL: http://llvm.org/viewvc/llvm-project/poolalloc/trunk/lib/DSA/TopDownClosure.cpp?rev=98700&r1=98699&r2=98700&view=diff ============================================================================== --- poolalloc/trunk/lib/DSA/TopDownClosure.cpp (original) +++ poolalloc/trunk/lib/DSA/TopDownClosure.cpp Tue Mar 16 20:00:46 2010 @@ -165,7 +165,7 @@ // Recursively traverse all of the callee graphs. for (DSGraph::fc_iterator CI = G->fc_begin(), CE = G->fc_end(); CI != CE; ++CI) - for (DSCallGraph::iterator I = callgraph.callee_begin(CI->getCallSite()), + for (DSCallGraph::callee_iterator I = callgraph.callee_begin(CI->getCallSite()), E = callgraph.callee_end(CI->getCallSite()); I != E; ++I) ComputePostOrder(**I, Visited, PostOrder); @@ -300,7 +300,7 @@ } // For each function in the invoked function list at this call site... - DSCallGraph::iterator IPI = callgraph.callee_begin(CI->getCallSite()), + DSCallGraph::callee_iterator IPI = callgraph.callee_begin(CI->getCallSite()), IPE = callgraph.callee_end(CI->getCallSite()); // Skip over all calls to this graph (SCC calls). @@ -332,7 +332,7 @@ // so we build up a new, private, graph that represents the calls of all // calls to this set of functions. std::vector Callees; - for (DSCallGraph::iterator I = callgraph.callee_begin(CI->getCallSite()), + for (DSCallGraph::callee_iterator I = callgraph.callee_begin(CI->getCallSite()), E = callgraph.callee_end(CI->getCallSite()); I != E; ++I) if (!(*I)->isDeclaration()) Callees.push_back(*I); Modified: poolalloc/trunk/lib/PoolAllocate/RunTimeAssociate.cpp URL: http://llvm.org/viewvc/llvm-project/poolalloc/trunk/lib/PoolAllocate/RunTimeAssociate.cpp?rev=98700&r1=98699&r2=98700&view=diff ============================================================================== --- poolalloc/trunk/lib/PoolAllocate/RunTimeAssociate.cpp (original) +++ poolalloc/trunk/lib/PoolAllocate/RunTimeAssociate.cpp Tue Mar 16 20:00:46 2010 @@ -461,7 +461,7 @@ Instruction *OrigInst = cast(FI.getOldValueIfAvailable(CS.getInstruction())); - DSCallGraph::iterator I = DS->getCallGraph().callee_begin(CS); + DSCallGraph::callee_iterator I = DS->getCallGraph().callee_begin(CS); if (I != DS->getCallGraph().callee_end(CS)) CF = *I; @@ -508,7 +508,7 @@ #ifndef NDEBUG // Verify that all potential callees at call site have the same DS graph. - DSCallGraph::iterator E = DS->getCallGraph().callee_end(CS); + DSCallGraph::callee_iterator E = DS->getCallGraph().callee_end(CS); for (; I != E; ++I) if (!(*I)->isDeclaration()) assert(CalleeGraph == DS->getDSGraph(**I) && Modified: poolalloc/trunk/lib/PoolAllocate/TransformFunctionBody.cpp URL: http://llvm.org/viewvc/llvm-project/poolalloc/trunk/lib/PoolAllocate/TransformFunctionBody.cpp?rev=98700&r1=98699&r2=98700&view=diff ============================================================================== --- poolalloc/trunk/lib/PoolAllocate/TransformFunctionBody.cpp (original) +++ poolalloc/trunk/lib/PoolAllocate/TransformFunctionBody.cpp Tue Mar 16 20:00:46 2010 @@ -645,7 +645,7 @@ Instruction *OrigInst = cast(getOldValueIfAvailable(CS.getInstruction())); - DSCallGraph::iterator I = Graphs.getCallGraph().callee_begin(CS); + DSCallGraph::callee_iterator I = Graphs.getCallGraph().callee_begin(CS); if (I != Graphs.getCallGraph().callee_end(CS)) CF = *I; @@ -685,7 +685,7 @@ #ifndef NDEBUG // Verify that all potential callees at call site have the same DS graph. - DSCallGraph::iterator E = Graphs.getCallGraph().callee_end(OrigInst); + DSCallGraph::callee_iterator E = Graphs.getCallGraph().callee_end(OrigInst); for (; I != E; ++I) if (!(*I)->isDeclaration()) assert(CalleeGraph == Graphs.getDSGraph(**I) && From jyasskin at google.com Tue Mar 16 20:18:45 2010 From: jyasskin at google.com (Jeffrey Yasskin) Date: Wed, 17 Mar 2010 01:18:45 -0000 Subject: [llvm-commits] [llvm] r98701 - in /llvm/trunk/unittests: ADT/APFloatTest.cpp ADT/APIntTest.cpp Support/LeakDetectorTest.cpp Message-ID: <20100317011845.6E8802A6C12C@llvm.org> Author: jyasskin Date: Tue Mar 16 20:18:45 2010 New Revision: 98701 URL: http://llvm.org/viewvc/llvm-project?rev=98701&view=rev Log: Fix death tests in -Asserts builds. Modified: llvm/trunk/unittests/ADT/APFloatTest.cpp llvm/trunk/unittests/ADT/APIntTest.cpp llvm/trunk/unittests/Support/LeakDetectorTest.cpp Modified: llvm/trunk/unittests/ADT/APFloatTest.cpp URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/unittests/ADT/APFloatTest.cpp?rev=98701&r1=98700&r2=98701&view=diff ============================================================================== --- llvm/trunk/unittests/ADT/APFloatTest.cpp (original) +++ llvm/trunk/unittests/ADT/APFloatTest.cpp Tue Mar 16 20:18:45 2010 @@ -374,6 +374,7 @@ } #ifdef GTEST_HAS_DEATH_TEST +#ifndef NDEBUG TEST(APFloatTest, SemanticsDeath) { EXPECT_DEATH(APFloat(APFloat::IEEEsingle, 0.0f).convertToDouble(), "Float semantics are not IEEEdouble"); EXPECT_DEATH(APFloat(APFloat::IEEEdouble, 0.0 ).convertToFloat(), "Float semantics are not IEEEsingle"); @@ -573,5 +574,6 @@ EXPECT_DEATH(APFloat(APFloat::IEEEdouble, "-0x1.1p-"), "Exponent has no digits"); } #endif +#endif } Modified: llvm/trunk/unittests/ADT/APIntTest.cpp URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/unittests/ADT/APIntTest.cpp?rev=98701&r1=98700&r2=98701&view=diff ============================================================================== --- llvm/trunk/unittests/ADT/APIntTest.cpp (original) +++ llvm/trunk/unittests/ADT/APIntTest.cpp Tue Mar 16 20:18:45 2010 @@ -328,6 +328,7 @@ } #ifdef GTEST_HAS_DEATH_TEST +#ifndef NDEBUG TEST(APIntTest, StringDeath) { EXPECT_DEATH(APInt(0, "", 0), "Bitwidth too small"); EXPECT_DEATH(APInt(32, "", 0), "Invalid string length"); @@ -340,5 +341,6 @@ EXPECT_DEATH(APInt(32, "1L", 10), "Invalid character in digit string"); } #endif +#endif } Modified: llvm/trunk/unittests/Support/LeakDetectorTest.cpp URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/unittests/Support/LeakDetectorTest.cpp?rev=98701&r1=98700&r2=98701&view=diff ============================================================================== --- llvm/trunk/unittests/Support/LeakDetectorTest.cpp (original) +++ llvm/trunk/unittests/Support/LeakDetectorTest.cpp Tue Mar 16 20:18:45 2010 @@ -15,6 +15,7 @@ namespace { #ifdef GTEST_HAS_DEATH_TEST +#ifndef NDEBUG TEST(LeakDetector, Death1) { LeakDetector::addGarbageObject((void*) 1); LeakDetector::addGarbageObject((void*) 2); @@ -25,5 +26,6 @@ "Cache != o && \"Object already in set!\""); } #endif +#endif } From stoklund at 2pi.dk Tue Mar 16 20:37:34 2010 From: stoklund at 2pi.dk (Jakob Stoklund Olesen) Date: Tue, 16 Mar 2010 18:37:34 -0700 Subject: [llvm-commits] [llvm] r98023 - /llvm/trunk/lib/CodeGen/SimpleRegisterCoalescing.cpp In-Reply-To: References: <20100309005948.483A02A6C12C@llvm.org> <59424131-A98B-428A-9BE7-75786CE199C4@2pi.dk> Message-ID: <8CB245DF-F632-42BA-88C8-46140C3321D6@2pi.dk> On Mar 16, 2010, at 11:27 AM, Chris Lattner wrote: > > On Mar 9, 2010, at 10:15 AM, Jakob Stoklund Olesen wrote: > >> >> On Mar 9, 2010, at 9:41 AM, Jakob Stoklund Olesen wrote: >> >>> >>> On Mar 8, 2010, at 5:37 PM, Jakob Stoklund Olesen wrote: >>> >>>> >>>> On Mar 8, 2010, at 5:23 PM, Evan Cheng wrote: >>>> >>>>> Is 1000 scientific? :-) >>>> >>> >>> The coalescer timing formed a perfect parabola with t=4.1s at N=2000. This is not a caching effect - the coalescer is quadratic in the number of function calls! >> >> The attached graph shows the coalescer runtime as a function of the array length in my tiny test function (inlining disabled). The patch kicks in at N=500 and reduces runtime to nothing. > > Is it possible to fix or improve the N^2 algorithm? Yes, I think so. From the end of SimpleJoin: // Update the liveintervals of sub-registers. if (TargetRegisterInfo::isPhysicalRegister(LHS.reg)) for (const unsigned *AS = tri_->getSubRegisters(LHS.reg); *AS; ++AS) li_->getOrCreateInterval(*AS).MergeInClobberRanges(*li_, LHS, li_->getVNInfoAllocator()); MergeInClobberRanges() is linear in the size of LHS, and SimpleJoin() is called once for each LiveRange in LHS -> quadratic runtime. However, SimpleJoin() is called to merge a trivial RHS into a complex LHS. It may be as simple as calling MergeClobberRanges(RHS) instead. I would have to read the code more closely. Ideally, I want to avoid physreg joining altogether, and use better hinting instead. Half of the coalescer would go away, and all of the bugs ;-) /jakob From clattner at apple.com Tue Mar 16 20:41:24 2010 From: clattner at apple.com (Chris Lattner) Date: Tue, 16 Mar 2010 18:41:24 -0700 Subject: [llvm-commits] [llvm] r98023 - /llvm/trunk/lib/CodeGen/SimpleRegisterCoalescing.cpp In-Reply-To: <8CB245DF-F632-42BA-88C8-46140C3321D6@2pi.dk> References: <20100309005948.483A02A6C12C@llvm.org> <59424131-A98B-428A-9BE7-75786CE199C4@2pi.dk> <8CB245DF-F632-42BA-88C8-46140C3321D6@2pi.dk> Message-ID: <306D339C-D88F-4AE7-B523-B1C6DA2FB219@apple.com> On Mar 16, 2010, at 6:37 PM, Jakob Stoklund Olesen wrote: >>> >>> The attached graph shows the coalescer runtime as a function of the array length in my tiny test function (inlining disabled). The patch kicks in at N=500 and reduces runtime to nothing. >> >> Is it possible to fix or improve the N^2 algorithm? > > Yes, I think so. From the end of SimpleJoin: > > // Update the liveintervals of sub-registers. > if (TargetRegisterInfo::isPhysicalRegister(LHS.reg)) > for (const unsigned *AS = tri_->getSubRegisters(LHS.reg); *AS; ++AS) > li_->getOrCreateInterval(*AS).MergeInClobberRanges(*li_, LHS, > li_->getVNInfoAllocator()); > > > MergeInClobberRanges() is linear in the size of LHS, and SimpleJoin() is called once for each LiveRange in LHS -> quadratic runtime. > > However, SimpleJoin() is called to merge a trivial RHS into a complex LHS. It may be as simple as calling MergeClobberRanges(RHS) instead. I would have to read the code more closely. Nice, definitely sounds like a worthwhile experiment. > Ideally, I want to avoid physreg joining altogether, and use better hinting instead. Half of the coalescer would go away, and all of the bugs ;-) cool, do that too! ;-) -Chris From sabre at nondot.org Tue Mar 16 20:45:17 2010 From: sabre at nondot.org (Chris Lattner) Date: Wed, 17 Mar 2010 01:45:17 -0000 Subject: [llvm-commits] [llvm] r98704 - /llvm/trunk/include/llvm/Target/TargetOptions.h Message-ID: <20100317014517.EE2122A6C12C@llvm.org> Author: lattner Date: Tue Mar 16 20:45:17 2010 New Revision: 98704 URL: http://llvm.org/viewvc/llvm-project?rev=98704&view=rev Log: remove dead variable, patch by Nathan Howell! Modified: llvm/trunk/include/llvm/Target/TargetOptions.h Modified: llvm/trunk/include/llvm/Target/TargetOptions.h URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/Target/TargetOptions.h?rev=98704&r1=98703&r2=98704&view=diff ============================================================================== --- llvm/trunk/include/llvm/Target/TargetOptions.h (original) +++ llvm/trunk/include/llvm/Target/TargetOptions.h Tue Mar 16 20:45:17 2010 @@ -144,11 +144,6 @@ /// wth earlier copy coalescing. extern bool StrongPHIElim; - /// DisableScheduling - This flag disables instruction scheduling. In - /// particular, it assigns an ordering to the SDNodes, which the scheduler - /// uses instead of its normal heuristics to perform scheduling. - extern bool DisableScheduling; - } // End llvm namespace #endif From jyasskin at google.com Tue Mar 16 20:58:51 2010 From: jyasskin at google.com (Jeffrey Yasskin) Date: Tue, 16 Mar 2010 18:58:51 -0700 Subject: [llvm-commits] [llvm] r98701 - in /llvm/trunk/unittests: ADT/APFloatTest.cpp ADT/APIntTest.cpp Support/LeakDetectorTest.cpp In-Reply-To: <20100317011845.6E8802A6C12C@llvm.org> References: <20100317011845.6E8802A6C12C@llvm.org> Message-ID: Hey Tanya, this patch lets the unittests pass in more configurations. Could you merge it to the 2.7 branch? It should apply cleanly. On Tue, Mar 16, 2010 at 6:18 PM, Jeffrey Yasskin wrote: > Author: jyasskin > Date: Tue Mar 16 20:18:45 2010 > New Revision: 98701 > > URL: http://llvm.org/viewvc/llvm-project?rev=98701&view=rev > Log: > Fix death tests in -Asserts builds. > > Modified: > ? ?llvm/trunk/unittests/ADT/APFloatTest.cpp > ? ?llvm/trunk/unittests/ADT/APIntTest.cpp > ? ?llvm/trunk/unittests/Support/LeakDetectorTest.cpp > > Modified: llvm/trunk/unittests/ADT/APFloatTest.cpp > URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/unittests/ADT/APFloatTest.cpp?rev=98701&r1=98700&r2=98701&view=diff > ============================================================================== > --- llvm/trunk/unittests/ADT/APFloatTest.cpp (original) > +++ llvm/trunk/unittests/ADT/APFloatTest.cpp Tue Mar 16 20:18:45 2010 > @@ -374,6 +374,7 @@ > ?} > > ?#ifdef GTEST_HAS_DEATH_TEST > +#ifndef NDEBUG > ?TEST(APFloatTest, SemanticsDeath) { > ? EXPECT_DEATH(APFloat(APFloat::IEEEsingle, 0.0f).convertToDouble(), "Float semantics are not IEEEdouble"); > ? EXPECT_DEATH(APFloat(APFloat::IEEEdouble, 0.0 ).convertToFloat(), ?"Float semantics are not IEEEsingle"); > @@ -573,5 +574,6 @@ > ? EXPECT_DEATH(APFloat(APFloat::IEEEdouble, "-0x1.1p-"), "Exponent has no digits"); > ?} > ?#endif > +#endif > > ?} > > Modified: llvm/trunk/unittests/ADT/APIntTest.cpp > URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/unittests/ADT/APIntTest.cpp?rev=98701&r1=98700&r2=98701&view=diff > ============================================================================== > --- llvm/trunk/unittests/ADT/APIntTest.cpp (original) > +++ llvm/trunk/unittests/ADT/APIntTest.cpp Tue Mar 16 20:18:45 2010 > @@ -328,6 +328,7 @@ > ?} > > ?#ifdef GTEST_HAS_DEATH_TEST > +#ifndef NDEBUG > ?TEST(APIntTest, StringDeath) { > ? EXPECT_DEATH(APInt(0, "", 0), "Bitwidth too small"); > ? EXPECT_DEATH(APInt(32, "", 0), "Invalid string length"); > @@ -340,5 +341,6 @@ > ? EXPECT_DEATH(APInt(32, "1L", 10), "Invalid character in digit string"); > ?} > ?#endif > +#endif > > ?} > > Modified: llvm/trunk/unittests/Support/LeakDetectorTest.cpp > URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/unittests/Support/LeakDetectorTest.cpp?rev=98701&r1=98700&r2=98701&view=diff > ============================================================================== > --- llvm/trunk/unittests/Support/LeakDetectorTest.cpp (original) > +++ llvm/trunk/unittests/Support/LeakDetectorTest.cpp Tue Mar 16 20:18:45 2010 > @@ -15,6 +15,7 @@ > ?namespace { > > ?#ifdef GTEST_HAS_DEATH_TEST > +#ifndef NDEBUG > ?TEST(LeakDetector, Death1) { > ? LeakDetector::addGarbageObject((void*) 1); > ? LeakDetector::addGarbageObject((void*) 2); > @@ -25,5 +26,6 @@ > ? ? ? ? ? ? ? ?"Cache != o && \"Object already in set!\""); > ?} > ?#endif > +#endif > > ?} > > > _______________________________________________ > llvm-commits mailing list > llvm-commits at cs.uiuc.edu > http://lists.cs.uiuc.edu/mailman/listinfo/llvm-commits > From sabre at nondot.org Tue Mar 16 23:02:39 2010 From: sabre at nondot.org (Chris Lattner) Date: Wed, 17 Mar 2010 04:02:39 -0000 Subject: [llvm-commits] [llvm] r98706 - /llvm/trunk/docs/ReleaseNotes.html Message-ID: <20100317040239.B885F2A6C12C@llvm.org> Author: lattner Date: Tue Mar 16 23:02:39 2010 New Revision: 98706 URL: http://llvm.org/viewvc/llvm-project?rev=98706&view=rev Log: add logo, comment out project info, they need to send updates to get reincluded. Modified: llvm/trunk/docs/ReleaseNotes.html Modified: llvm/trunk/docs/ReleaseNotes.html URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/docs/ReleaseNotes.html?rev=98706&r1=98705&r2=98706&view=diff ============================================================================== --- llvm/trunk/docs/ReleaseNotes.html (original) +++ llvm/trunk/docs/ReleaseNotes.html Tue Mar 16 23:02:39 2010 @@ -10,6 +10,9 @@
LLVM 2.7 Release Notes
+ +
  1. Introduction
  2. Sub-project Status Update
  3. @@ -139,7 +142,7 @@ in C and Objective-C programs. The tool performs checks to find bugs that occur on a specific path within a program.

    -

    In the LLVM 2.7 time-frame, the analyzer core has ...

    +

    In the LLVM 2.7 time-frame, the analyzer core has sprouted legs and...

    @@ -257,6 +260,8 @@
    +Need update. +

    @@ -278,6 +284,8 @@

    +Need update. +

    @@ -299,6 +307,8 @@

    +Need update. +

    @@ -321,6 +331,8 @@

    +Need update. +

    @@ -339,10 +351,13 @@

    +Need update. +

    @@ -352,10 +367,13 @@

    +Need update. + +

    @@ -365,10 +383,13 @@

    +Need update. + +

    @@ -378,13 +399,15 @@

    +Need update. +

    From nicholas at mxc.ca Tue Mar 16 23:32:54 2010 From: nicholas at mxc.ca (Nick Lewycky) Date: Tue, 16 Mar 2010 21:32:54 -0700 Subject: [llvm-commits] [llvm] r98634 - /llvm/trunk/unittests/VMCore/InstructionsTest.cpp In-Reply-To: <20100316155358.966292A6C12C@llvm.org> References: <20100316155358.966292A6C12C@llvm.org> Message-ID: <4BA05B76.80101@mxc.ca> Gabor Greif wrote: > Author: ggreif > Date: Tue Mar 16 10:53:58 2010 > New Revision: 98634 > > URL: http://llvm.org/viewvc/llvm-project?rev=98634&view=rev > Log: > more BranchInst tests > > Modified: > llvm/trunk/unittests/VMCore/InstructionsTest.cpp > > Modified: llvm/trunk/unittests/VMCore/InstructionsTest.cpp > URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/unittests/VMCore/InstructionsTest.cpp?rev=98634&r1=98633&r2=98634&view=diff > ============================================================================== > --- llvm/trunk/unittests/VMCore/InstructionsTest.cpp (original) > +++ llvm/trunk/unittests/VMCore/InstructionsTest.cpp Tue Mar 16 10:53:58 2010 > @@ -50,10 +50,17 @@ > // Mandatory BranchInst > const BranchInst* b0 = BranchInst::Create(bb0); > > + EXPECT_TRUE(b0->isUnconditional()); > + EXPECT_FALSE(b0->isConditional()); > + EXPECT_EQ(b0->getNumSuccessors(), 1U); > + > // check num operands > EXPECT_EQ(b0->getNumOperands(), 1U); > > EXPECT_NE(b0->op_begin(), b0->op_end()); > + EXPECT_EQ(b0->op_begin() + 1, b0->op_end()); Consider using llvm::next(b0->op_begin()) defined in include/llvm/ADT/STLExtras.h . I'm assuming that this test passes for you, but I don't normally expect that I can take iterator + 1 in LLVM because it often gets me a pointer addition. Nick > + > + EXPECT_EQ(b0->op_begin() + 1, b0->op_end()); > > const IntegerType* Int1 = IntegerType::get(C, 1); > Constant* One = ConstantInt::get(Int1, 1, true); > @@ -61,6 +68,10 @@ > // Conditional BranchInst > BranchInst* b1 = BranchInst::Create(bb0, bb1, One); > > + EXPECT_FALSE(b1->isUnconditional()); > + EXPECT_TRUE(b1->isConditional()); > + EXPECT_EQ(b1->getNumSuccessors(), 2U); > + > // check num operands > EXPECT_EQ(b1->getNumOperands(), 3U); > > @@ -70,16 +81,19 @@ > EXPECT_NE(b, b1->op_end()); > EXPECT_EQ(*b, One); > EXPECT_EQ(b1->getOperand(0), One); > + EXPECT_EQ(b1->getCondition(), One); > ++b; > > // check ELSE > EXPECT_EQ(*b, bb1); > EXPECT_EQ(b1->getOperand(1), bb1); > + EXPECT_EQ(b1->getSuccessor(1), bb1); > ++b; > > // check THEN > EXPECT_EQ(*b, bb0); > EXPECT_EQ(b1->getOperand(2), bb0); > + EXPECT_EQ(b1->getSuccessor(0), bb0); > ++b; > > EXPECT_EQ(b, b1->op_end()); > @@ -96,6 +110,7 @@ > // check THEN > EXPECT_EQ(*c, bb1); > EXPECT_EQ(b1->getOperand(0), bb1); > + EXPECT_EQ(b1->getSuccessor(0), bb1); > ++c; > > EXPECT_EQ(c, b1->op_end()); > > > _______________________________________________ > llvm-commits mailing list > llvm-commits at cs.uiuc.edu > http://lists.cs.uiuc.edu/mailman/listinfo/llvm-commits > From sabre at nondot.org Tue Mar 16 23:41:49 2010 From: sabre at nondot.org (Chris Lattner) Date: Wed, 17 Mar 2010 04:41:49 -0000 Subject: [llvm-commits] [llvm] r98709 - /llvm/trunk/docs/ReleaseNotes.html Message-ID: <20100317044149.3111C2A6C12C@llvm.org> Author: lattner Date: Tue Mar 16 23:41:49 2010 New Revision: 98709 URL: http://llvm.org/viewvc/llvm-project?rev=98709&view=rev Log: add a bunch of random and unformatted notes as I am reading through tons of old commits. Modified: llvm/trunk/docs/ReleaseNotes.html Modified: llvm/trunk/docs/ReleaseNotes.html URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/docs/ReleaseNotes.html?rev=98709&r1=98708&r2=98709&view=diff ============================================================================== --- llvm/trunk/docs/ReleaseNotes.html (original) +++ llvm/trunk/docs/ReleaseNotes.html Tue Mar 16 23:41:49 2010 @@ -51,14 +51,17 @@

    For more information about LLVM, including information about the latest release, please check out the main LLVM web site. If you have questions or comments, the LLVM Developer's Mailing -List is a good place to send them.

    +href="http://lists.cs.uiuc.edu/mailman/listinfo/llvmdev">LLVM Developer's +Mailing List is a good place to send them.

    Note that if you are reading this file from a Subversion checkout or the main LLVM web page, this document applies to the next release, not the current one. To see the release notes for a specific release, please see the releases page.

    + +

    FIXME: llvm.org moved to new server, mention new logo.

    + @@ -441,6 +444,33 @@
  4. ...
  5. +Extensible metadata solid. + +Debug info improvements: using metadata instead of llvm.dbg global variables. +This brings several enhancements including improved compile times. + +New instruction selector. +GHC Haskell ABI/ calling conv support. +Pre-Alpha support for unions in IR. +New InlineHint and StackAlignment function attributes +Code generator MC'ized except for debug info and EH. +New SCEV AA pass: -scev-aa +Inliner reuses arrays allocas when inlining multiple callers to reduce stack usage. +MC encoding and disassembler apis. +Optimal Edge Profiling? +Instcombine is now a library, has its own IRBuilder to simplify itself. +New llvm/Support/Regex.h API. FileCheck now does regex's + + + + +AndersAA got removed (from 2.7 or mainline?) +LLVM command line tools now overwrite their output, before they would only do this with -f. +DOUT removed, use DEBUG(errs() instead. +Much stuff converted to use raw_ostream instead of std::ostream. +TargetAsmInfo renamed to MCAsmInfo +llvm/ADT/iterator.h gone. + @@ -757,7 +787,8 @@
  6. The MSIL, Alpha, SPU, MIPS, PIC16, Blackfin, MSP430 and SystemZ backends are experimental.
  7. The llc "-filetype=asm" (the default) is the only - supported value for this option. The ELF writer is experimental.
  8. + supported value for this option. The MachO writer is experimental, and + works much better in mainline SVN. @@ -888,7 +919,7 @@
    @@ -906,24 +937,6 @@ - -
    - -

    The C++ front-end is considered to be fully -tested and works for a number of non-trivial programs, including LLVM -itself, Qt, Mozilla, etc.

    - -
      -
    • Exception handling works well on the X86 and PowerPC targets. Currently - only Linux and Darwin targets are supported (both 32 and 64 bit).
    • -
    - -
    - - - From sabre at nondot.org Wed Mar 17 00:16:35 2010 From: sabre at nondot.org (Chris Lattner) Date: Wed, 17 Mar 2010 05:16:35 -0000 Subject: [llvm-commits] [www] r98711 - /www/trunk/OpenProjects.html Message-ID: <20100317051635.205E92A6C12C@llvm.org> Author: lattner Date: Wed Mar 17 00:16:34 2010 New Revision: 98711 URL: http://llvm.org/viewvc/llvm-project?rev=98711&view=rev Log: add a potential gsoc project. Modified: www/trunk/OpenProjects.html Modified: www/trunk/OpenProjects.html URL: http://llvm.org/viewvc/llvm-project/www/trunk/OpenProjects.html?rev=98711&r1=98710&r2=98711&view=diff ============================================================================== --- www/trunk/OpenProjects.html (original) +++ www/trunk/OpenProjects.html Wed Mar 17 00:16:34 2010 @@ -197,6 +197,9 @@
      +
    1. Completely rewrite bugpoint. In addition to being a mess, bugpoint suffers +from a number of problems where it will "lose" a bug when reducing. It should +be rewritten from scratch to solve these and other problems.
    2. Add support for transactions to the PassManager for improved bugpoint.
    3. Improve bugpoint to From sabre at nondot.org Wed Mar 17 00:41:19 2010 From: sabre at nondot.org (Chris Lattner) Date: Wed, 17 Mar 2010 05:41:19 -0000 Subject: [llvm-commits] [llvm] r98712 - in /llvm/trunk: include/llvm/MC/MCContext.h lib/CodeGen/GCStrategy.cpp lib/MC/MCContext.cpp lib/Target/TargetLoweringObjectFile.cpp lib/Target/X86/AsmPrinter/X86MCInstLower.cpp Message-ID: <20100317054119.34A4F2A6C12C@llvm.org> Author: lattner Date: Wed Mar 17 00:41:18 2010 New Revision: 98712 URL: http://llvm.org/viewvc/llvm-project?rev=98712&view=rev Log: fix GetOrCreateTemporarySymbol to require a name, clients should use CreateTempSymbol() if they don't care about the name. Modified: llvm/trunk/include/llvm/MC/MCContext.h llvm/trunk/lib/CodeGen/GCStrategy.cpp llvm/trunk/lib/MC/MCContext.cpp llvm/trunk/lib/Target/TargetLoweringObjectFile.cpp llvm/trunk/lib/Target/X86/AsmPrinter/X86MCInstLower.cpp Modified: llvm/trunk/include/llvm/MC/MCContext.h URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/MC/MCContext.h?rev=98712&r1=98711&r2=98712&view=diff ============================================================================== --- llvm/trunk/include/llvm/MC/MCContext.h (original) +++ llvm/trunk/include/llvm/MC/MCContext.h Wed Mar 17 00:41:18 2010 @@ -73,9 +73,10 @@ /// one if it does. /// /// @param Name - The symbol name, for debugging purposes only, temporary - /// symbols do not surive assembly. If non-empty the name must be unique - /// across all symbols. - MCSymbol *GetOrCreateTemporarySymbol(StringRef Name = ""); + /// symbols do not surive assembly. + MCSymbol *GetOrCreateTemporarySymbol(StringRef Name) { + return GetOrCreateSymbol(Name, true); + } MCSymbol *GetOrCreateTemporarySymbol(const Twine &Name); /// LookupSymbol - Get the symbol for \p Name, or null. Modified: llvm/trunk/lib/CodeGen/GCStrategy.cpp URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/CodeGen/GCStrategy.cpp?rev=98712&r1=98711&r2=98712&view=diff ============================================================================== --- llvm/trunk/lib/CodeGen/GCStrategy.cpp (original) +++ llvm/trunk/lib/CodeGen/GCStrategy.cpp Wed Mar 17 00:41:18 2010 @@ -332,7 +332,7 @@ MCSymbol *MachineCodeAnalysis::InsertLabel(MachineBasicBlock &MBB, MachineBasicBlock::iterator MI, DebugLoc DL) const { - MCSymbol *Label = MBB.getParent()->getContext().GetOrCreateTemporarySymbol(); + MCSymbol *Label = MBB.getParent()->getContext().CreateTempSymbol(); BuildMI(MBB, MI, DL, TII->get(TargetOpcode::GC_LABEL)).addSym(Label); return Label; } Modified: llvm/trunk/lib/MC/MCContext.cpp URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/MC/MCContext.cpp?rev=98712&r1=98711&r2=98712&view=diff ============================================================================== --- llvm/trunk/lib/MC/MCContext.cpp (original) +++ llvm/trunk/lib/MC/MCContext.cpp Wed Mar 17 00:41:18 2010 @@ -49,17 +49,6 @@ "tmp" + Twine(NextUniqueID++)); } - -MCSymbol *MCContext::GetOrCreateTemporarySymbol(StringRef Name) { - // If there is no name, create a new anonymous symbol. - // FIXME: Remove this. This form of the method should always take a name. - if (Name.empty()) - return GetOrCreateTemporarySymbol(Twine(MAI.getPrivateGlobalPrefix()) + - "tmp" + Twine(NextUniqueID++)); - - return GetOrCreateSymbol(Name, true); -} - MCSymbol *MCContext::GetOrCreateTemporarySymbol(const Twine &Name) { SmallString<128> NameSV; Name.toVector(NameSV); Modified: llvm/trunk/lib/Target/TargetLoweringObjectFile.cpp URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Target/TargetLoweringObjectFile.cpp?rev=98712&r1=98711&r2=98712&view=diff ============================================================================== --- llvm/trunk/lib/Target/TargetLoweringObjectFile.cpp (original) +++ llvm/trunk/lib/Target/TargetLoweringObjectFile.cpp Wed Mar 17 00:41:18 2010 @@ -317,7 +317,7 @@ case dwarf::DW_EH_PE_pcrel: { // Emit a label to the streamer for the current position. This gives us // .-foo addressing. - MCSymbol *PCSym = getContext().GetOrCreateTemporarySymbol(); + MCSymbol *PCSym = getContext().CreateTempSymbol(); Streamer.EmitLabel(PCSym); const MCExpr *PC = MCSymbolRefExpr::Create(PCSym, getContext()); return MCBinaryExpr::CreateSub(Res, PC, getContext()); Modified: llvm/trunk/lib/Target/X86/AsmPrinter/X86MCInstLower.cpp URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Target/X86/AsmPrinter/X86MCInstLower.cpp?rev=98712&r1=98711&r2=98712&view=diff ============================================================================== --- llvm/trunk/lib/Target/X86/AsmPrinter/X86MCInstLower.cpp (original) +++ llvm/trunk/lib/Target/X86/AsmPrinter/X86MCInstLower.cpp Wed Mar 17 00:41:18 2010 @@ -427,7 +427,7 @@ // MYGLOBAL + (. - PICBASE) // However, we can't generate a ".", so just emit a new label here and refer // to it. - MCSymbol *DotSym = OutContext.GetOrCreateTemporarySymbol(); + MCSymbol *DotSym = OutContext.CreateTempSymbol(); OutStreamer.EmitLabel(DotSym); // Now that we have emitted the label, lower the complex operand expression. From evan.cheng at apple.com Wed Mar 17 01:19:48 2010 From: evan.cheng at apple.com (Evan Cheng) Date: Tue, 16 Mar 2010 23:19:48 -0700 Subject: [llvm-commits] [llvm] r98023 - /llvm/trunk/lib/CodeGen/SimpleRegisterCoalescing.cpp In-Reply-To: <306D339C-D88F-4AE7-B523-B1C6DA2FB219@apple.com> References: <20100309005948.483A02A6C12C@llvm.org> <59424131-A98B-428A-9BE7-75786CE199C4@2pi.dk> <8CB245DF-F632-42BA-88C8-46140C3321D6@2pi.dk> <306D339C-D88F-4AE7-B523-B1C6DA2FB219@apple.com> Message-ID: <1643FF41-32A6-41EE-8CA5-3776585ACB74@apple.com> On Mar 16, 2010, at 6:41 PM, Chris Lattner wrote: > > On Mar 16, 2010, at 6:37 PM, Jakob Stoklund Olesen wrote: > >>>> >>>> The attached graph shows the coalescer runtime as a function of the array length in my tiny test function (inlining disabled). The patch kicks in at N=500 and reduces runtime to nothing. >>> >>> Is it possible to fix or improve the N^2 algorithm? >> >> Yes, I think so. From the end of SimpleJoin: >> >> // Update the liveintervals of sub-registers. >> if (TargetRegisterInfo::isPhysicalRegister(LHS.reg)) >> for (const unsigned *AS = tri_->getSubRegisters(LHS.reg); *AS; ++AS) >> li_->getOrCreateInterval(*AS).MergeInClobberRanges(*li_, LHS, >> li_->getVNInfoAllocator()); >> >> >> MergeInClobberRanges() is linear in the size of LHS, and SimpleJoin() is called once for each LiveRange in LHS -> quadratic runtime. >> >> However, SimpleJoin() is called to merge a trivial RHS into a complex LHS. It may be as simple as calling MergeClobberRanges(RHS) instead. I would have to read the code more closely. > > Nice, definitely sounds like a worthwhile experiment. > >> Ideally, I want to avoid physreg joining altogether, and use better hinting instead. Half of the coalescer would go away, and all of the bugs ;-) That's the proper way to fix this. But we are ready to just do this yet. At least not with the short comings of linear scan. Evan > > cool, do that too! ;-) > > -Chris > _______________________________________________ > llvm-commits mailing list > llvm-commits at cs.uiuc.edu > http://lists.cs.uiuc.edu/mailman/listinfo/llvm-commits From sabre at nondot.org Wed Mar 17 01:42:25 2010 From: sabre at nondot.org (Chris Lattner) Date: Wed, 17 Mar 2010 06:42:25 -0000 Subject: [llvm-commits] [llvm] r98715 - /llvm/trunk/docs/ReleaseNotes.html Message-ID: <20100317064225.987152A6C12D@llvm.org> Author: lattner Date: Wed Mar 17 01:42:25 2010 New Revision: 98715 URL: http://llvm.org/viewvc/llvm-project?rev=98715&view=rev Log: combiner-aa too, what's its status? Modified: llvm/trunk/docs/ReleaseNotes.html Modified: llvm/trunk/docs/ReleaseNotes.html URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/docs/ReleaseNotes.html?rev=98715&r1=98714&r2=98715&view=diff ============================================================================== --- llvm/trunk/docs/ReleaseNotes.html (original) +++ llvm/trunk/docs/ReleaseNotes.html Wed Mar 17 01:42:25 2010 @@ -474,6 +474,7 @@ New SSAUpdater and MachineSSAUpdater classes for unstructured ssa updating, changed jump threading, GVN, etc to use it which simplified them and speed them up. +Combiner-AA improvements, why not on by default? CondProp pass removed (functionality merged into jump threading). AndersAA got removed (from 2.7 or mainline?) From sabre at nondot.org Wed Mar 17 01:41:58 2010 From: sabre at nondot.org (Chris Lattner) Date: Wed, 17 Mar 2010 06:41:58 -0000 Subject: [llvm-commits] [llvm] r98714 - /llvm/trunk/docs/ReleaseNotes.html Message-ID: <20100317064158.727F32A6C12C@llvm.org> Author: lattner Date: Wed Mar 17 01:41:58 2010 New Revision: 98714 URL: http://llvm.org/viewvc/llvm-project?rev=98714&view=rev Log: more chris scribble. Modified: llvm/trunk/docs/ReleaseNotes.html Modified: llvm/trunk/docs/ReleaseNotes.html URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/docs/ReleaseNotes.html?rev=98714&r1=98713&r2=98714&view=diff ============================================================================== --- llvm/trunk/docs/ReleaseNotes.html (original) +++ llvm/trunk/docs/ReleaseNotes.html Wed Mar 17 01:41:58 2010 @@ -60,7 +60,8 @@ releases page.

      -

      FIXME: llvm.org moved to new server, mention new logo.

      +

      FIXME: llvm.org moved to new server, mention new logo, Ted and Doug new code + owners.

    @@ -72,6 +73,7 @@ llvm/Analysis/PointerTracking.h => Edwin wants this, consider for 2.8. ABCD, SCCVN, GEPSplitterPass MSIL backend? + lib/Transforms/Utils/SSI.cpp -> ABCD depends on it. --> @@ -84,8 +86,6 @@ loop dependence analysis ELF Writer? How stable?
  9. PostRA scheduler improvements, ARM adoption (David Goodwin).
  10. - 2.7 supports the GDB 7.0 jit interfaces for debug info. - 2.7 eliminates ADT/iterator.h --> @@ -129,6 +128,7 @@
    • ...
    • +include a link to cxx_compatibility.html
    @@ -460,17 +460,31 @@ Optimal Edge Profiling? Instcombine is now a library, has its own IRBuilder to simplify itself. New llvm/Support/Regex.h API. FileCheck now does regex's +Many subtle pointer invalidation bugs in Callgraph have been fixed and it now uses asserting value handles. +MC Disassembler (with blog post), MCInstPrinter. Many X86 backend and AsmPrinter simplifications +Various tools like llc and opt now read either .ll or .bc files as input. +Malloc and free instructions got removed. +compiler-rt support for ARM. +completely llvm-gcc NEON support. +Can transcode from GAS to intel syntax with "llvm-mc foo.s -output-asm-variant=1" +JIT debug information with GDB 7.0 +New CodeGen Level LICM And CSE (did it make 2.7?) +CMake can now run tests, what other improvements? +ARM/Thumb register scavenging improvements? +New SSAUpdater and MachineSSAUpdater classes for unstructured ssa updating, + changed jump threading, GVN, etc to use it which simplified them and speed + them up. - - - +CondProp pass removed (functionality merged into jump threading). AndersAA got removed (from 2.7 or mainline?) +PredSimplify, LoopVR, GVNPRE got removed. LLVM command line tools now overwrite their output, before they would only do this with -f. DOUT removed, use DEBUG(errs() instead. Much stuff converted to use raw_ostream instead of std::ostream. TargetAsmInfo renamed to MCAsmInfo llvm/ADT/iterator.h gone. + From evan.cheng at apple.com Wed Mar 17 01:48:11 2010 From: evan.cheng at apple.com (Evan Cheng) Date: Tue, 16 Mar 2010 23:48:11 -0700 Subject: [llvm-commits] [llvm] r98714 - /llvm/trunk/docs/ReleaseNotes.html In-Reply-To: <20100317064158.727F32A6C12C@llvm.org> References: <20100317064158.727F32A6C12C@llvm.org> Message-ID: <18DC0521-E879-4C58-86B8-0591B43FA9C5@apple.com> On Mar 16, 2010, at 11:41 PM, Chris Lattner wrote: > Author: lattner > Date: Wed Mar 17 01:41:58 2010 > New Revision: 98714 > > URL: http://llvm.org/viewvc/llvm-project?rev=98714&view=rev > Log: > more chris scribble. > > Modified: > llvm/trunk/docs/ReleaseNotes.html > > Modified: llvm/trunk/docs/ReleaseNotes.html > URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/docs/ReleaseNotes.html?rev=98714&r1=98713&r2=98714&view=diff > ============================================================================== > --- llvm/trunk/docs/ReleaseNotes.html (original) > +++ llvm/trunk/docs/ReleaseNotes.html Wed Mar 17 01:41:58 2010 > @@ -60,7 +60,8 @@ > releases page.

    > > > -

    FIXME: llvm.org moved to new server, mention new logo.

    > +

    FIXME: llvm.org moved to new server, mention new logo, Ted and Doug new code > + owners.

    > > > > @@ -72,6 +73,7 @@ > llvm/Analysis/PointerTracking.h => Edwin wants this, consider for 2.8. > ABCD, SCCVN, GEPSplitterPass > MSIL backend? > + lib/Transforms/Utils/SSI.cpp -> ABCD depends on it. > --> > > > @@ -84,8 +86,6 @@ > loop dependence analysis > ELF Writer? How stable? >
  11. PostRA scheduler improvements, ARM adoption (David Goodwin).
  12. > - 2.7 supports the GDB 7.0 jit interfaces for debug info. > - 2.7 eliminates ADT/iterator.h > --> > > > > > @@ -129,6 +128,7 @@ > >
      >
    • ...
    • > +include a link to cxx_compatibility.html >
    > > > @@ -460,17 +460,31 @@ > Optimal Edge Profiling? > Instcombine is now a library, has its own IRBuilder to simplify itself. > New llvm/Support/Regex.h API. FileCheck now does regex's > +Many subtle pointer invalidation bugs in Callgraph have been fixed and it now uses asserting value handles. > +MC Disassembler (with blog post), MCInstPrinter. Many X86 backend and AsmPrinter simplifications > +Various tools like llc and opt now read either .ll or .bc files as input. > +Malloc and free instructions got removed. > +compiler-rt support for ARM. > +completely llvm-gcc NEON support. > +Can transcode from GAS to intel syntax with "llvm-mc foo.s -output-asm-variant=1" > +JIT debug information with GDB 7.0 > +New CodeGen Level LICM And CSE (did it make 2.7?) LICM is not new. CSE made into 2.7. > +CMake can now run tests, what other improvements? > +ARM/Thumb register scavenging improvements? Using reg scavenging for stack object address materialization (PEI). > +New SSAUpdater and MachineSSAUpdater classes for unstructured ssa updating, > + changed jump threading, GVN, etc to use it which simplified them and speed > + them up. Some other codegen changes: Pre-regalloc tail duplication x86 sibcall optimization New LSR with full strength reduction mode And don't forget the most awesome sext / zext optimization pass. :-) Evan > > - > - > - > +CondProp pass removed (functionality merged into jump threading). > AndersAA got removed (from 2.7 or mainline?) > +PredSimplify, LoopVR, GVNPRE got removed. > LLVM command line tools now overwrite their output, before they would only do this with -f. > DOUT removed, use DEBUG(errs() instead. > Much stuff converted to use raw_ostream instead of std::ostream. > TargetAsmInfo renamed to MCAsmInfo > llvm/ADT/iterator.h gone. > > + > > > > > > _______________________________________________ > llvm-commits mailing list > llvm-commits at cs.uiuc.edu > http://lists.cs.uiuc.edu/mailman/listinfo/llvm-commits From jyasskin at google.com Wed Mar 17 02:08:12 2010 From: jyasskin at google.com (Jeffrey Yasskin) Date: Wed, 17 Mar 2010 07:08:12 -0000 Subject: [llvm-commits] [llvm] r98716 - /llvm/trunk/lib/System/Unix/Signals.inc Message-ID: <20100317070812.458292A6C12C@llvm.org> Author: jyasskin Date: Wed Mar 17 02:08:12 2010 New Revision: 98716 URL: http://llvm.org/viewvc/llvm-project?rev=98716&view=rev Log: Fix a false-positive memory leak in code using RemoveFileOnSignal(). Because libstdc++'s std::string class points to the interior of an allocation, valgrind reports strings still alive at program termination as possible leaks. I didn't use a ManagedStatic for this because System can't depend on Support. Modified: llvm/trunk/lib/System/Unix/Signals.inc Modified: llvm/trunk/lib/System/Unix/Signals.inc URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/System/Unix/Signals.inc?rev=98716&r1=98715&r2=98716&view=diff ============================================================================== --- llvm/trunk/lib/System/Unix/Signals.inc (original) +++ llvm/trunk/lib/System/Unix/Signals.inc Wed Mar 17 02:08:12 2010 @@ -39,8 +39,8 @@ /// InterruptFunction - The function to call if ctrl-c is pressed. static void (*InterruptFunction)() = 0; -static std::vector *FilesToRemove = 0; -static std::vector > *CallBacksToRun = 0; +static std::vector FilesToRemove; +static std::vector > CallBacksToRun; // IntSigs - Signals that may interrupt the program at any time. static const int IntSigs[] = { @@ -126,11 +126,10 @@ sigprocmask(SIG_UNBLOCK, &SigMask, 0); SignalsMutex.acquire(); - if (FilesToRemove != 0) - while (!FilesToRemove->empty()) { - FilesToRemove->back().eraseFromDisk(true); - FilesToRemove->pop_back(); - } + while (!FilesToRemove.empty()) { + FilesToRemove.back().eraseFromDisk(true); + FilesToRemove.pop_back(); + } if (std::find(IntSigs, IntSigsEnd, Sig) != IntSigsEnd) { if (InterruptFunction) { @@ -149,9 +148,8 @@ SignalsMutex.release(); // Otherwise if it is a fault (like SEGV) run any handler. - if (CallBacksToRun) - for (unsigned i = 0, e = CallBacksToRun->size(); i != e; ++i) - (*CallBacksToRun)[i].first((*CallBacksToRun)[i].second); + for (unsigned i = 0, e = CallBacksToRun.size(); i != e; ++i) + CallBacksToRun[i].first(CallBacksToRun[i].second); } @@ -167,10 +165,7 @@ bool llvm::sys::RemoveFileOnSignal(const sys::Path &Filename, std::string* ErrMsg) { SignalsMutex.acquire(); - if (FilesToRemove == 0) - FilesToRemove = new std::vector(); - - FilesToRemove->push_back(Filename); + FilesToRemove.push_back(Filename); SignalsMutex.release(); @@ -182,9 +177,7 @@ /// to the process. The handler can have a cookie passed to it to identify /// what instance of the handler it is. void llvm::sys::AddSignalHandler(void (*FnPtr)(void *), void *Cookie) { - if (CallBacksToRun == 0) - CallBacksToRun = new std::vector >(); - CallBacksToRun->push_back(std::make_pair(FnPtr, Cookie)); + CallBacksToRun.push_back(std::make_pair(FnPtr, Cookie)); RegisterHandlers(); } From stoklund at 2pi.dk Wed Mar 17 09:25:13 2010 From: stoklund at 2pi.dk (Jakob Stoklund Olesen) Date: Wed, 17 Mar 2010 07:25:13 -0700 Subject: [llvm-commits] [llvm] r98023 - /llvm/trunk/lib/CodeGen/SimpleRegisterCoalescing.cpp In-Reply-To: <1643FF41-32A6-41EE-8CA5-3776585ACB74@apple.com> References: <20100309005948.483A02A6C12C@llvm.org> <59424131-A98B-428A-9BE7-75786CE199C4@2pi.dk> <8CB245DF-F632-42BA-88C8-46140C3321D6@2pi.dk> <306D339C-D88F-4AE7-B523-B1C6DA2FB219@apple.com> <1643FF41-32A6-41EE-8CA5-3776585ACB74@apple.com> Message-ID: On Mar 16, 2010, at 11:19 PM, Evan Cheng wrote: >> On Mar 16, 2010, at 6:37 PM, Jakob Stoklund Olesen wrote: >>> Ideally, I want to avoid physreg joining altogether, and use better hinting instead. Half of the coalescer would go away, and all of the bugs ;-) > > That's the proper way to fix this. But we are ready to just do this yet. At least not with the short comings of linear scan. Do we know what those shortcomings are? My plan is to calculate hints at the same time as spill weights, instead of during coalescing. That allows a weighted vote in case there are multiple physreg copies of the same vreg. (Right now, the vote goes to whatever physreg was seen last.) Second, I want to recalculate hints (and possibly spill weights) after breaking up a live interval for spilling. In a perfect world, we could eliminate the trivial coalescing pass after register allocation too. One problem is that linear scan resets the hints when it is backtracking, are there others? /jakob From criswell at uiuc.edu Wed Mar 17 10:01:50 2010 From: criswell at uiuc.edu (John Criswell) Date: Wed, 17 Mar 2010 15:01:50 -0000 Subject: [llvm-commits] [llvm] r98724 - /llvm/trunk/docs/SourceLevelDebugging.html Message-ID: <20100317150150.ED8C52A6C12C@llvm.org> Author: criswell Date: Wed Mar 17 10:01:50 2010 New Revision: 98724 URL: http://llvm.org/viewvc/llvm-project?rev=98724&view=rev Log: Fixed spelling errors. Modified: llvm/trunk/docs/SourceLevelDebugging.html Modified: llvm/trunk/docs/SourceLevelDebugging.html URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/docs/SourceLevelDebugging.html?rev=98724&r1=98723&r2=98724&view=diff ============================================================================== --- llvm/trunk/docs/SourceLevelDebugging.html (original) +++ llvm/trunk/docs/SourceLevelDebugging.html Wed Mar 17 10:01:50 2010 @@ -237,7 +237,7 @@

    LLVM debugging information has been carefully designed to make it possible for the optimizer to optimize the program and debugging information without necessarily having to know anything about debugging information. In - particular, te use of metadadta avoids duplicated dubgging information from + particular, the use of metadata avoids duplicated debugging information from the beginning, and the global dead code elimination pass automatically deletes debugging information for a function if it decides to delete the function.

    @@ -370,7 +370,7 @@ -

    These descriptors contain informations for a file. Global variables and top +

    These descriptors contain information for a file. Global variables and top level functions would be defined using this context.k File descriptors also provide context for source line correspondence.

    @@ -967,7 +967,7 @@ -

    Here !14 indicates that Z is declaread at line number 5 and +

    Here !14 indicates that Z is declared at line number 5 and column number 9 inside of lexical scope !13. The lexical scope itself resides inside of lexical scope !1 described above.

    From bob.wilson at apple.com Wed Mar 17 10:46:53 2010 From: bob.wilson at apple.com (Bob Wilson) Date: Wed, 17 Mar 2010 08:46:53 -0700 Subject: [llvm-commits] [llvm] r98679 - in /llvm/trunk/lib/Target/ARM: ARMInstrInfo.td ARMInstrVFP.td In-Reply-To: <20100316212506.1176A2A6C12C@llvm.org> References: <20100316212506.1176A2A6C12C@llvm.org> Message-ID: <238CF4E8-13D1-4ACB-AEB9-221C7C2FDEF7@apple.com> These variants are already distinguished by IndexModeNone vs. IndexModeUpd. Can you use that distinction to determine the writeback bit? On Mar 16, 2010, at 2:25 PM, Johnny Chen wrote: > Author: johnny > Date: Tue Mar 16 16:25:05 2010 > New Revision: 98679 > > URL: http://llvm.org/viewvc/llvm-project?rev=98679&view=rev > Log: > Disambiguate the *_UPD and * variants by specifying the writeback flag as 1. > This is for the disassembly work. > > There are cases where this is not possible, for example, A8.6.53 LDM Encoding T1. > In such case, we'll use an adhoc approach to deduce the Opcode programmatically. > > Modified: > llvm/trunk/lib/Target/ARM/ARMInstrInfo.td > llvm/trunk/lib/Target/ARM/ARMInstrVFP.td > > Modified: llvm/trunk/lib/Target/ARM/ARMInstrInfo.td > URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Target/ARM/ARMInstrInfo.td?rev=98679&r1=98678&r2=98679&view=diff > ============================================================================== > --- llvm/trunk/lib/Target/ARM/ARMInstrInfo.td (original) > +++ llvm/trunk/lib/Target/ARM/ARMInstrInfo.td Tue Mar 16 16:25:05 2010 > @@ -1355,7 +1355,9 @@ > reglist:$dsts, variable_ops), > IndexModeUpd, LdStMulFrm, IIC_iLoadm, > "ldm${addr:submode}${p}\t$addr!, $dsts", > - "$addr.addr = $wb", []>; > + "$addr.addr = $wb", []> { > + let Inst{21} = 1; // wback > +} > } // mayLoad, hasExtraDefRegAllocReq > > let mayStore = 1, hasExtraSrcRegAllocReq = 1 in { > @@ -1368,7 +1370,9 @@ > reglist:$srcs, variable_ops), > IndexModeUpd, LdStMulFrm, IIC_iStorem, > "stm${addr:submode}${p}\t$addr!, $srcs", > - "$addr.addr = $wb", []>; > + "$addr.addr = $wb", []> { > + let Inst{21} = 1; // wback > +} > } // mayStore, hasExtraSrcRegAllocReq > > //===----------------------------------------------------------------------===// > > Modified: llvm/trunk/lib/Target/ARM/ARMInstrVFP.td > URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Target/ARM/ARMInstrVFP.td?rev=98679&r1=98678&r2=98679&view=diff > ============================================================================== > --- llvm/trunk/lib/Target/ARM/ARMInstrVFP.td (original) > +++ llvm/trunk/lib/Target/ARM/ARMInstrVFP.td Tue Mar 16 16:25:05 2010 > @@ -96,6 +96,7 @@ > IndexModeUpd, IIC_fpLoadm, > "vldm${addr:submode}${p}\t${addr:base}!, $dsts", > "$addr.base = $wb", []> { > + let Inst{21} = 1; // wback > let Inst{20} = 1; > } > > @@ -104,6 +105,7 @@ > IndexModeUpd, IIC_fpLoadm, > "vldm${addr:submode}${p}\t${addr:base}!, $dsts", > "$addr.base = $wb", []> { > + let Inst{21} = 1; // wback > let Inst{20} = 1; > } > } // mayLoad, hasExtraDefRegAllocReq > @@ -126,6 +128,7 @@ > IndexModeUpd, IIC_fpStorem, > "vstm${addr:submode}${p}\t${addr:base}!, $srcs", > "$addr.base = $wb", []> { > + let Inst{21} = 1; // wback > let Inst{20} = 0; > } > > @@ -134,6 +137,7 @@ > IndexModeUpd, IIC_fpStorem, > "vstm${addr:submode}${p}\t${addr:base}!, $srcs", > "$addr.base = $wb", []> { > + let Inst{21} = 1; // wback > let Inst{20} = 0; > } > } // mayStore, hasExtraSrcRegAllocReq > > > _______________________________________________ > llvm-commits mailing list > llvm-commits at cs.uiuc.edu > http://lists.cs.uiuc.edu/mailman/listinfo/llvm-commits From stuart at apple.com Wed Mar 17 10:59:15 2010 From: stuart at apple.com (Stuart Hastings) Date: Wed, 17 Mar 2010 15:59:15 -0000 Subject: [llvm-commits] [llvm-gcc-4.2] r98728 - /llvm-gcc-4.2/trunk/gcc/llvm-convert.cpp Message-ID: <20100317155915.205E22A6C12C@llvm.org> Author: stuart Date: Wed Mar 17 10:59:14 2010 New Revision: 98728 URL: http://llvm.org/viewvc/llvm-project?rev=98728&view=rev Log: Use GCC-specd type when referencing ObjC2 bitfields. Radar 7639995. Modified: llvm-gcc-4.2/trunk/gcc/llvm-convert.cpp Modified: llvm-gcc-4.2/trunk/gcc/llvm-convert.cpp URL: http://llvm.org/viewvc/llvm-project/llvm-gcc-4.2/trunk/gcc/llvm-convert.cpp?rev=98728&r1=98727&r2=98728&view=diff ============================================================================== --- llvm-gcc-4.2/trunk/gcc/llvm-convert.cpp (original) +++ llvm-gcc-4.2/trunk/gcc/llvm-convert.cpp Wed Mar 17 10:59:14 2010 @@ -7021,6 +7021,11 @@ LVAlign = MinAlign(LVAlign, ByteOffset); } + // Since we're using GCC's offset, we're obliged to use GCC's + // "shrink-wrapped" type for the reference, lest we reference + // memory outside of this struct. + FieldTy = ConvertType(TREE_TYPE(FieldDecl)); + Value *Ptr = CastToType(Instruction::PtrToInt, StructAddrLV.Ptr, Offset->getType()); Ptr = Builder.CreateAdd(Ptr, Offset); From andrewl at lenharth.org Wed Mar 17 11:29:18 2010 From: andrewl at lenharth.org (Andrew Lenharth) Date: Wed, 17 Mar 2010 16:29:18 -0000 Subject: [llvm-commits] [poolalloc] r98732 - in /poolalloc/trunk: include/dsa/DSCallGraph.h include/dsa/DSNode.h include/dsa/DataStructure.h include/dsa/super_set.h include/dsa/svset.h lib/DSA/BottomUpClosure.cpp lib/DSA/DataStructure.cpp lib/DSA/Local.cpp lib/DSA/Printer.cpp lib/DSA/TopDownClosure.cpp Message-ID: <20100317162918.6022E2A6C12C@llvm.org> Author: alenhar2 Date: Wed Mar 17 11:29:18 2010 New Revision: 98732 URL: http://llvm.org/viewvc/llvm-project?rev=98732&view=rev Log: move headers and rename sv::set Added: poolalloc/trunk/include/dsa/super_set.h - copied, changed from r98698, poolalloc/trunk/include/dsa/sv/super_set.h poolalloc/trunk/include/dsa/svset.h - copied, changed from r98699, poolalloc/trunk/include/dsa/sv/set.h Modified: poolalloc/trunk/include/dsa/DSCallGraph.h poolalloc/trunk/include/dsa/DSNode.h poolalloc/trunk/include/dsa/DataStructure.h poolalloc/trunk/lib/DSA/BottomUpClosure.cpp poolalloc/trunk/lib/DSA/DataStructure.cpp poolalloc/trunk/lib/DSA/Local.cpp poolalloc/trunk/lib/DSA/Printer.cpp poolalloc/trunk/lib/DSA/TopDownClosure.cpp Modified: poolalloc/trunk/include/dsa/DSCallGraph.h URL: http://llvm.org/viewvc/llvm-project/poolalloc/trunk/include/dsa/DSCallGraph.h?rev=98732&r1=98731&r2=98732&view=diff ============================================================================== --- poolalloc/trunk/include/dsa/DSCallGraph.h (original) +++ poolalloc/trunk/include/dsa/DSCallGraph.h Wed Mar 17 11:29:18 2010 @@ -14,7 +14,7 @@ #ifndef LLVM_DSCALLGRAPH_H #define LLVM_DSCALLGRAPH_H -#include "dsa/sv/set.h" +#include "dsa/svset.h" #include #include "llvm/Function.h" @@ -98,7 +98,7 @@ class DSCallGraph { public: - typedef sv::set FuncSet; + typedef svset FuncSet; typedef std::map ActualCalleesTy; typedef std::map SimpleCalleesTy; @@ -210,10 +210,10 @@ unsigned nextSCC; //Functions we know about that aren't called - sv::set knownRoots; + svset knownRoots; - std::map > SCCCallees; - std::map > ExtCallees; + std::map > SCCCallees; + std::map > ExtCallees; DSCallGraph oldGraph; @@ -306,14 +306,14 @@ } void buildRoots() { - sv::set knownCallees; - sv::set knownCallers; - for (std::map >::iterator + svset knownCallees; + svset knownCallers; + for (std::map >::iterator ii = SCCCallees.begin(), ee = SCCCallees.end(); ii != ee; ++ii) { knownCallees.insert(ii->second.begin(), ii->second.end()); knownCallers.insert(ii->first); } - for (sv::set::iterator ii = knownCallers.begin(), + for (svset::iterator ii = knownCallers.begin(), ee = knownCallers.end(); ii != ee; ++ii) if (!knownCallees.count(*ii)) knownRoots.insert(*ii); @@ -368,10 +368,10 @@ // llvm::errs() << ii->first << " -> " << ii->second << "\n"; //SCC map - for (std::map >::iterator ii = SCCCallees.begin(), + for (std::map >::iterator ii = SCCCallees.begin(), ee = SCCCallees.end(); ii != ee; ++ii) { llvm::errs() << "CallGraph[" << ii->first << "]"; - for (sv::set::iterator i = ii->second.begin(), + for (svset::iterator i = ii->second.begin(), e = ii->second.end(); i != e; ++i) llvm::errs() << " " << *i; llvm::errs() << "\n"; @@ -379,7 +379,7 @@ //Functions we know about that aren't called llvm::errs() << "Roots:"; - for (sv::set::iterator ii = knownRoots.begin(), + for (svset::iterator ii = knownRoots.begin(), ee = knownRoots.end(); ii != ee; ++ii) llvm::errs() << " " << *ii; llvm::errs() << "\n"; Modified: poolalloc/trunk/include/dsa/DSNode.h URL: http://llvm.org/viewvc/llvm-project/poolalloc/trunk/include/dsa/DSNode.h?rev=98732&r1=98731&r2=98732&view=diff ============================================================================== --- poolalloc/trunk/include/dsa/DSNode.h (original) +++ poolalloc/trunk/include/dsa/DSNode.h Wed Mar 17 11:29:18 2010 @@ -20,8 +20,8 @@ #include #include -#include "dsa/sv/set.h" -#include "dsa/sv/super_set.h" +#include "dsa/svset.h" +#include "dsa/super_set.h" #include "DSGraph.h" namespace llvm { @@ -79,7 +79,7 @@ /// Globals - The list of global values that are merged into this node. /// - sv::set Globals; + svset Globals; void operator=(const DSNode &); // DO NOT IMPLEMENT DSNode(const DSNode &); // DO NOT IMPLEMENT @@ -317,7 +317,7 @@ /// value leaders set that is merged into this node. Like the getGlobalsList /// method, these iterators do not return globals that are part of the /// equivalence classes for globals in this node, but aren't leaders. - typedef sv::set::const_iterator globals_iterator; + typedef svset::const_iterator globals_iterator; globals_iterator globals_begin() const { return Globals.begin(); } globals_iterator globals_end() const { return Globals.end(); } Modified: poolalloc/trunk/include/dsa/DataStructure.h URL: http://llvm.org/viewvc/llvm-project/poolalloc/trunk/include/dsa/DataStructure.h?rev=98732&r1=98731&r2=98732&view=diff ============================================================================== --- poolalloc/trunk/include/dsa/DataStructure.h (original) +++ poolalloc/trunk/include/dsa/DataStructure.h Wed Mar 17 11:29:18 2010 @@ -21,8 +21,8 @@ #include "dsa/EntryPointAnalysis.h" #include "dsa/DSCallGraph.h" -#include "dsa/sv/set.h" -#include "dsa/sv/super_set.h" +#include "dsa/svset.h" +#include "dsa/super_set.h" #include @@ -57,9 +57,9 @@ /// Were are DSGraphs stolen by another pass? bool DSGraphsStolen; - void buildGlobalECs(sv::set& ECGlobals); + void buildGlobalECs(svset& ECGlobals); - void eliminateUsesOfECGlobals(DSGraph& G, const sv::set &ECGlobals); + void eliminateUsesOfECGlobals(DSGraph& G, const svset &ECGlobals); // DSInfo, one graph for each function DSInfoTy DSInfo; @@ -237,7 +237,7 @@ private: void mergeSCCs(DSSCCGraph& DSG); - DSGraph* postOrder(DSSCCGraph& DSG, unsigned scc, sv::set& marked); + DSGraph* postOrder(DSSCCGraph& DSG, unsigned scc, svset& marked); void calculateGraph(DSGraph* G, DSSCCGraph& DSG); @@ -301,7 +301,7 @@ /// by the bottom-up pass. /// class TDDataStructures : public DataStructures { - sv::set ArgsRemainIncomplete; + svset ArgsRemainIncomplete; /// CallerCallEdges - For a particular graph, we keep a list of these records /// which indicates which graphs call this function and from where. @@ -353,10 +353,10 @@ private: void markReachableFunctionsExternallyAccessible(DSNode *N, - sv::set &Visited); + svset &Visited); void InlineCallersIntoGraph(DSGraph* G); - void ComputePostOrder(const Function &F, sv::set &Visited, + void ComputePostOrder(const Function &F, svset &Visited, std::vector &PostOrder); }; Copied: poolalloc/trunk/include/dsa/super_set.h (from r98698, poolalloc/trunk/include/dsa/sv/super_set.h) URL: http://llvm.org/viewvc/llvm-project/poolalloc/trunk/include/dsa/super_set.h?p2=poolalloc/trunk/include/dsa/super_set.h&p1=poolalloc/trunk/include/dsa/sv/super_set.h&r1=98698&r2=98732&rev=98732&view=diff ============================================================================== --- poolalloc/trunk/include/dsa/sv/super_set.h (original) +++ poolalloc/trunk/include/dsa/super_set.h Wed Mar 17 11:29:18 2010 @@ -8,7 +8,7 @@ #ifndef _SUPER_SET_H #define _SUPER_SET_H -#include "./set.h" +#include "dsa/svset.h" #include // Contains stable references to a set @@ -17,19 +17,19 @@ template class SuperSet { //std::set provides stable iterators, and that matters a lot - typedef sv::set InnerSetTy; + typedef svset InnerSetTy; typedef std::set OuterSetTy; OuterSetTy container; public: typedef const typename OuterSetTy::value_type* setPtr; - setPtr getOrCreate(sv::set& S) { + setPtr getOrCreate(svset& S) { if (S.empty()) return 0; return &(*container.insert(S).first); } setPtr getOrCreate(setPtr P, Ty t) { - sv::set s; + svset s; if (P) s.insert(P->begin(), P->end()); s.insert(t); Copied: poolalloc/trunk/include/dsa/svset.h (from r98699, poolalloc/trunk/include/dsa/sv/set.h) URL: http://llvm.org/viewvc/llvm-project/poolalloc/trunk/include/dsa/svset.h?p2=poolalloc/trunk/include/dsa/svset.h&p1=poolalloc/trunk/include/dsa/sv/set.h&r1=98699&r2=98732&rev=98732&view=diff ============================================================================== --- poolalloc/trunk/include/dsa/sv/set.h (original) +++ poolalloc/trunk/include/dsa/svset.h Wed Mar 17 11:29:18 2010 @@ -3,15 +3,14 @@ #include -namespace sv { - //////////////////////////////////////////////////////////////////////////////////////////////////// /// A set implemented atop a sorted vector. +/// Iterators are not stable accross insert or delete template< typename Key, typename Compare = std::less, typename Alloc = std::allocator > -class set { +class svset { typedef std::vector internal_type; // Types @@ -45,24 +44,24 @@ public: /// Empty constructor. - set() + svset() : container_() { } /// Constructor taking a range. template< typename Iterator > - set(const Iterator& begin, const Iterator& end) + svset(const Iterator& begin, const Iterator& end) : container_(begin, end) { sort_unique(); } /// Copy-constructor. - set(const set& rhs) + svset(const svset& rhs) : container_(rhs.container_) {} /// Affectation of a sorted vector to another one. - set & operator=(const set& rhs) { + svset & operator=(const svset& rhs) { if (&rhs != this) { this->container_ = rhs.container_; } @@ -159,7 +158,7 @@ } /// Swap the content of two sorted_vector. - void swap(set& s) { + void swap(svset& s) { container_.swap(s.container_); } @@ -199,10 +198,10 @@ /// Tells if this sorted vector is equal to another one. - bool operator==(const set& rhs) const { + bool operator==(const svset& rhs) const { return container_ == rhs.container_; } - bool operator<(const set& rhs) const { + bool operator<(const svset& rhs) const { if (rhs.size() < size()) return false; if (size() < rhs.size()) return true; const_iterator ii = begin(); @@ -223,6 +222,4 @@ //////////////////////////////////////////////////////////////////////////////////////////////////// -} // end of namespace sv - #endif // _SV_ORDERED_SET_HH_ Modified: poolalloc/trunk/lib/DSA/BottomUpClosure.cpp URL: http://llvm.org/viewvc/llvm-project/poolalloc/trunk/lib/DSA/BottomUpClosure.cpp?rev=98732&r1=98731&r2=98732&view=diff ============================================================================== --- poolalloc/trunk/lib/DSA/BottomUpClosure.cpp (original) +++ poolalloc/trunk/lib/DSA/BottomUpClosure.cpp Wed Mar 17 11:29:18 2010 @@ -69,8 +69,8 @@ //Post order traversal: { //errs() << *DSG.knownRoots.begin() << " -> " << *DSG.knownRoots.rbegin() << "\n"; - sv::set marked; - for (sv::set::const_iterator ii = DSG.knownRoots.begin(), + svset marked; + for (svset::const_iterator ii = DSG.knownRoots.begin(), ee = DSG.knownRoots.end(); ii != ee; ++ii) { //errs() << *ii << " "; DSGraph* G = postOrder(DSG, *ii, marked); @@ -196,11 +196,11 @@ } DSGraph* BUDataStructures::postOrder(DSSCCGraph& DSG, unsigned scc, - sv::set& marked) { + svset& marked) { DSGraph* G = getDSGraph(**DSG.SCCs[scc].begin()); if (marked.count(scc)) return G; - for(sv::set::iterator ii = DSG.SCCCallees[scc].begin(), + for(svset::iterator ii = DSG.SCCCallees[scc].begin(), ee = DSG.SCCCallees[scc].end(); ii != ee; ++ii) postOrder(DSG, *ii, marked); Modified: poolalloc/trunk/lib/DSA/DataStructure.cpp URL: http://llvm.org/viewvc/llvm-project/poolalloc/trunk/lib/DSA/DataStructure.cpp?rev=98732&r1=98731&r2=98732&view=diff ============================================================================== --- poolalloc/trunk/lib/DSA/DataStructure.cpp (original) +++ poolalloc/trunk/lib/DSA/DataStructure.cpp Wed Mar 17 11:29:18 2010 @@ -53,7 +53,7 @@ DEBUG( { //assert not looping DSNode* NH = N; - sv::set seen; + svset seen; while(NH && NH->isForwarding()) { assert(seen.find(NH) == seen.end() && "Loop detected"); seen.insert(NH); @@ -339,7 +339,7 @@ if (!TyMap[Offset]) TyMap[Offset] = TyIt; if (TyIt) { - sv::set S(*TyMap[Offset]); + svset S(*TyMap[Offset]); S.insert(TyIt->begin(), TyIt->end()); TyMap[Offset] = getParentGraph()->getTypeSS().getOrCreate(S); } @@ -1125,7 +1125,7 @@ void DataStructures::formGlobalECs() { // Grow the equivalence classes for the globals to include anything that we // now know to be aliased. - sv::set ECGlobals; + svset ECGlobals; buildGlobalECs(ECGlobals); if (!ECGlobals.empty()) { DEBUG(errs() << "Eliminating " << ECGlobals.size() << " EC Globals!\n"); @@ -1140,7 +1140,7 @@ /// apart. Instead of maintaining this information in all of the graphs /// throughout the entire program, store only a single global (the "leader") in /// the graphs, and build equivalence classes for the rest of the globals. -void DataStructures::buildGlobalECs(sv::set &ECGlobals) { +void DataStructures::buildGlobalECs(svset &ECGlobals) { DSScalarMap &SM = GlobalsGraph->getScalarMap(); EquivalenceClasses &GlobalECs = SM.getGlobalECs(); for (DSGraph::node_iterator I = GlobalsGraph->node_begin(), @@ -1179,7 +1179,7 @@ /// really just equivalent to some other globals, remove the globals from the /// specified DSGraph (if present), and merge any nodes with their leader nodes. void DataStructures::eliminateUsesOfECGlobals(DSGraph &G, - const sv::set &ECGlobals) { + const svset &ECGlobals) { DSScalarMap &SM = G.getScalarMap(); EquivalenceClasses &GlobalECs = SM.getGlobalECs(); Modified: poolalloc/trunk/lib/DSA/Local.cpp URL: http://llvm.org/viewvc/llvm-project/poolalloc/trunk/lib/DSA/Local.cpp?rev=98732&r1=98731&r2=98732&view=diff ============================================================================== --- poolalloc/trunk/lib/DSA/Local.cpp (original) +++ poolalloc/trunk/lib/DSA/Local.cpp Wed Mar 17 11:29:18 2010 @@ -880,7 +880,7 @@ while (count) { std::string section; msf >> section; - sv::set inSection; + svset inSection; for (Module::iterator MI = M.begin(), ME = M.end(); MI != ME; ++MI) if (MI->hasSection() && MI->getSection() == section) @@ -896,7 +896,7 @@ Value* V = M.getNamedValue(global); if (V) { DSNodeHandle& DHV = GlobalsGraph->getNodeForValue(V); - for (sv::set::iterator SI = inSection.begin(), + for (svset::iterator SI = inSection.begin(), SE = inSection.end(); SI != SE; ++SI) { DEBUG(errs() << "Merging " << V->getNameStr() << " with " << (*SI)->getNameStr() << "\n"); Modified: poolalloc/trunk/lib/DSA/Printer.cpp URL: http://llvm.org/viewvc/llvm-project/poolalloc/trunk/lib/DSA/Printer.cpp?rev=98732&r1=98731&r2=98732&view=diff ============================================================================== --- poolalloc/trunk/lib/DSA/Printer.cpp (original) +++ poolalloc/trunk/lib/DSA/Printer.cpp Wed Mar 17 11:29:18 2010 @@ -65,7 +65,7 @@ ee = N->type_end(); ii != ee; ++ii) { OS << ii->first << ": "; if (ii->second) - for (sv::set::const_iterator ni = ii->second->begin(), + for (svset::const_iterator ni = ii->second->begin(), ne = ii->second->end(); ni != ne; ++ni) { WriteTypeSymbolic(OS, *ni, M); OS << ", "; Modified: poolalloc/trunk/lib/DSA/TopDownClosure.cpp URL: http://llvm.org/viewvc/llvm-project/poolalloc/trunk/lib/DSA/TopDownClosure.cpp?rev=98732&r1=98731&r2=98732&view=diff ============================================================================== --- poolalloc/trunk/lib/DSA/TopDownClosure.cpp (original) +++ poolalloc/trunk/lib/DSA/TopDownClosure.cpp Wed Mar 17 11:29:18 2010 @@ -54,7 +54,7 @@ } void TDDataStructures::markReachableFunctionsExternallyAccessible(DSNode *N, - sv::set &Visited) { + svset &Visited) { if (!N || Visited.count(N)) return; Visited.insert(N); @@ -85,7 +85,7 @@ // arguments are functions which are reachable by global variables in the // globals graph. const DSScalarMap &GGSM = GlobalsGraph->getScalarMap(); - sv::set Visited; + svset Visited; for (DSScalarMap::global_iterator I=GGSM.global_begin(), E=GGSM.global_end(); I != E; ++I) { DSNode *N = GGSM.find(*I)->second.getNode(); @@ -114,7 +114,7 @@ // We want to traverse the call graph in reverse post-order. To do this, we // calculate a post-order traversal, then reverse it. - sv::set VisitedGraph; + svset VisitedGraph; std::vector PostOrder; {TIME_REGION(XXX, "td:Compute postorder"); @@ -156,7 +156,7 @@ void TDDataStructures::ComputePostOrder(const Function &F, - sv::set &Visited, + svset &Visited, std::vector &PostOrder) { if (F.isDeclaration()) return; DSGraph* G = getOrCreateGraph(&F); From andrewl at lenharth.org Wed Mar 17 11:30:14 2010 From: andrewl at lenharth.org (Andrew Lenharth) Date: Wed, 17 Mar 2010 16:30:14 -0000 Subject: [llvm-commits] [poolalloc] r98733 - /poolalloc/trunk/include/dsa/sv/ Message-ID: <20100317163014.15AFB2A6C12C@llvm.org> Author: alenhar2 Date: Wed Mar 17 11:30:13 2010 New Revision: 98733 URL: http://llvm.org/viewvc/llvm-project?rev=98733&view=rev Log: remove the dir properly this time Removed: poolalloc/trunk/include/dsa/sv/ From baldrick at free.fr Wed Mar 17 11:30:43 2010 From: baldrick at free.fr (Duncan Sands) Date: Wed, 17 Mar 2010 17:30:43 +0100 Subject: [llvm-commits] [llvm-gcc-4.2] r98728 - /llvm-gcc-4.2/trunk/gcc/llvm-convert.cpp In-Reply-To: <20100317155915.205E22A6C12C@llvm.org> References: <20100317155915.205E22A6C12C@llvm.org> Message-ID: <4BA103B3.50404@free.fr> Hi Stuart, > Use GCC-specd type when referencing ObjC2 bitfields. Radar 7639995. I never understood why llvm-gcc insists on using the "declared type" and not the gcc layed out bitfield types, which are much more logical from a low-level point of view. Ciao, Duncan. From clattner at apple.com Wed Mar 17 11:37:15 2010 From: clattner at apple.com (Chris Lattner) Date: Wed, 17 Mar 2010 09:37:15 -0700 Subject: [llvm-commits] [llvm-gcc-4.2] r98728 - /llvm-gcc-4.2/trunk/gcc/llvm-convert.cpp In-Reply-To: <20100317155915.205E22A6C12C@llvm.org> References: <20100317155915.205E22A6C12C@llvm.org> Message-ID: <00A80928-1795-4EBC-BA54-F7D8E1BB3A36@apple.com> testcase? On Mar 17, 2010, at 8:59 AM, Stuart Hastings wrote: > Author: stuart > Date: Wed Mar 17 10:59:14 2010 > New Revision: 98728 > > URL: http://llvm.org/viewvc/llvm-project?rev=98728&view=rev > Log: > Use GCC-specd type when referencing ObjC2 bitfields. Radar 7639995. > > Modified: > llvm-gcc-4.2/trunk/gcc/llvm-convert.cpp > > Modified: llvm-gcc-4.2/trunk/gcc/llvm-convert.cpp > URL: http://llvm.org/viewvc/llvm-project/llvm-gcc-4.2/trunk/gcc/llvm-convert.cpp?rev=98728&r1=98727&r2=98728&view=diff > ============================================================================== > --- llvm-gcc-4.2/trunk/gcc/llvm-convert.cpp (original) > +++ llvm-gcc-4.2/trunk/gcc/llvm-convert.cpp Wed Mar 17 10:59:14 2010 > @@ -7021,6 +7021,11 @@ > LVAlign = MinAlign(LVAlign, ByteOffset); > } > > + // Since we're using GCC's offset, we're obliged to use GCC's > + // "shrink-wrapped" type for the reference, lest we reference > + // memory outside of this struct. > + FieldTy = ConvertType(TREE_TYPE(FieldDecl)); > + > Value *Ptr = CastToType(Instruction::PtrToInt, StructAddrLV.Ptr, > Offset->getType()); > Ptr = Builder.CreateAdd(Ptr, Offset); > > > _______________________________________________ > llvm-commits mailing list > llvm-commits at cs.uiuc.edu > http://lists.cs.uiuc.edu/mailman/listinfo/llvm-commits From sabre at nondot.org Wed Mar 17 11:41:44 2010 From: sabre at nondot.org (Chris Lattner) Date: Wed, 17 Mar 2010 16:41:44 -0000 Subject: [llvm-commits] [llvm-gcc-4.2] r98739 - /llvm-gcc-4.2/trunk/gcc/llvm-linker-hack.cpp Message-ID: <20100317164144.A803A2A6C12C@llvm.org> Author: lattner Date: Wed Mar 17 11:41:44 2010 New Revision: 98739 URL: http://llvm.org/viewvc/llvm-project?rev=98739&view=rev Log: Fix this code to build with gcc 4.5, PR6632, patch by Bernhard Rosenkraenzer! Modified: llvm-gcc-4.2/trunk/gcc/llvm-linker-hack.cpp Modified: llvm-gcc-4.2/trunk/gcc/llvm-linker-hack.cpp URL: http://llvm.org/viewvc/llvm-project/llvm-gcc-4.2/trunk/gcc/llvm-linker-hack.cpp?rev=98739&r1=98738&r2=98739&view=diff ============================================================================== --- llvm-gcc-4.2/trunk/gcc/llvm-linker-hack.cpp (original) +++ llvm-gcc-4.2/trunk/gcc/llvm-linker-hack.cpp Wed Mar 17 11:41:44 2010 @@ -93,8 +93,8 @@ llvm::Type::getInt8Ty(llvm::getGlobalContext()); - llvm::PrettyStackTraceProgram::PrettyStackTraceProgram(0, 0); - llvm::DIFactory::DIFactory(*static_cast(0)); + llvm::PrettyStackTraceProgram(0, 0); + llvm::DIFactory(*static_cast(0)); std::string Err; llvm::TargetRegistry::lookupTarget("", Err); } From andrewl at lenharth.org Wed Mar 17 11:50:21 2010 From: andrewl at lenharth.org (Andrew Lenharth) Date: Wed, 17 Mar 2010 16:50:21 -0000 Subject: [llvm-commits] [poolalloc] r98740 - in /poolalloc/trunk/include/dsa: DSCallGraph.h keyiterator.h Message-ID: <20100317165021.1DC032A6C12C@llvm.org> Author: alenhar2 Date: Wed Mar 17 11:50:20 2010 New Revision: 98740 URL: http://llvm.org/viewvc/llvm-project?rev=98740&view=rev Log: split key iterator into seperate file Added: poolalloc/trunk/include/dsa/keyiterator.h - copied, changed from r98732, poolalloc/trunk/include/dsa/DSCallGraph.h Modified: poolalloc/trunk/include/dsa/DSCallGraph.h Modified: poolalloc/trunk/include/dsa/DSCallGraph.h URL: http://llvm.org/viewvc/llvm-project/poolalloc/trunk/include/dsa/DSCallGraph.h?rev=98740&r1=98739&r2=98740&view=diff ============================================================================== --- poolalloc/trunk/include/dsa/DSCallGraph.h (original) +++ poolalloc/trunk/include/dsa/DSCallGraph.h Wed Mar 17 11:50:20 2010 @@ -15,6 +15,7 @@ #define LLVM_DSCALLGRAPH_H #include "dsa/svset.h" +#include "dsa/keyiterator.h" #include #include "llvm/Function.h" @@ -22,79 +23,6 @@ #include "llvm/Support/CallSite.h" #include "llvm/Support/FormattedStream.h" -template -class KeyIterator { - Iter I; - -public: - typedef typename Iter::difference_type difference_type; - typedef typename Iter::value_type::first_type value_type; - typedef typename Iter::value_type::first_type* pointer; - typedef typename Iter::value_type::first_type& reference; - typedef typename Iter::iterator_category iterator_category; - - KeyIterator(Iter i) : I(i) { } - - Iter base() const { - return I; - } - - reference operator*() const { - return I->first; - } - - KeyIterator operator+(difference_type n) const { - return KeyIterator(I + n); - } - - KeyIterator & operator++() { - ++I; - return *this; - } - - KeyIterator operator++(int) { - Iter OI = I; - ++I; - return KeyIterator(OI); - } - - KeyIterator & operator+=(difference_type n) { - I += n; - return *this; - } - - KeyIterator operator-(difference_type n) const { - return KeyIterator(I - n); - } - - KeyIterator & operator--() { - --I; - return *this; - } - - KeyIterator operator--(int) { - Iter OI = I; - --I; - return KeyIterator(OI); - } - - KeyIterator & operator-=(difference_type n) { - I -= n; - return *this; - } - - pointer operator->() const { - return &I->first; - } - - bool operator==(const KeyIterator& RHS) const { - return I == RHS.I; - } - - bool operator!=(const KeyIterator& RHS) const { - return I != RHS.I; - } -}; class DSCallGraph { public: Copied: poolalloc/trunk/include/dsa/keyiterator.h (from r98732, poolalloc/trunk/include/dsa/DSCallGraph.h) URL: http://llvm.org/viewvc/llvm-project/poolalloc/trunk/include/dsa/keyiterator.h?p2=poolalloc/trunk/include/dsa/keyiterator.h&p1=poolalloc/trunk/include/dsa/DSCallGraph.h&r1=98732&r2=98740&rev=98740&view=diff ============================================================================== --- poolalloc/trunk/include/dsa/DSCallGraph.h (original) +++ poolalloc/trunk/include/dsa/keyiterator.h Wed Mar 17 11:50:20 2010 @@ -1,4 +1,4 @@ -//===- DSCallGaph.h - Build call graphs -------------------------*- C++ -*-===// +//===- keyiterator.h - Iterator over just the keys in a map -----*- C++ -*-===// // // The LLVM Compiler Infrastructure // @@ -7,20 +7,12 @@ // //===----------------------------------------------------------------------===// // -// Implement a detailed call graph for DSA. +// Implement a map key iterator // //===----------------------------------------------------------------------===// -#ifndef LLVM_DSCALLGRAPH_H -#define LLVM_DSCALLGRAPH_H - -#include "dsa/svset.h" -#include - -#include "llvm/Function.h" -#include "llvm/DerivedTypes.h" -#include "llvm/Support/CallSite.h" -#include "llvm/Support/FormattedStream.h" +#ifndef LLVM_KEYITERATOR_H +#define LLVM_KEYITERATOR_H template class KeyIterator { @@ -96,296 +88,5 @@ } }; -class DSCallGraph { -public: - typedef svset FuncSet; - typedef std::map ActualCalleesTy; - typedef std::map SimpleCalleesTy; - -private: - ActualCalleesTy ActualCallees; - SimpleCalleesTy SimpleCallees; - - FuncSet EmptyActual; - FuncSet EmptySimple; - -public: - - DSCallGraph() {} - - typedef ActualCalleesTy::mapped_type::const_iterator callee_iterator; - typedef KeyIterator key_iterator; - typedef SimpleCalleesTy::mapped_type::const_iterator flat_iterator; - typedef KeyIterator flat_key_iterator; - - void insert(llvm::CallSite CS, const llvm::Function* F) { - if (F) { - ActualCallees[CS].insert(F); - SimpleCallees[CS.getInstruction()->getParent()->getParent()].insert(F); - //Create an empty set for the callee, hence all called functions get to be - // in the call graph also. This simplifies SCC formation - SimpleCallees[F]; - } - } - - template - void insert(llvm::CallSite CS, Iterator _begin, Iterator _end) { - for (; _begin != _end; ++_begin) - insert(CS, *_begin); - } - - callee_iterator callee_begin(llvm::CallSite CS) const { - ActualCalleesTy::const_iterator ii = ActualCallees.find(CS); - if (ii == ActualCallees.end()) - return EmptyActual.end(); - return ii->second.begin(); - } - - callee_iterator callee_end(llvm::CallSite CS) const { - ActualCalleesTy::const_iterator ii = ActualCallees.find(CS); - if (ii == ActualCallees.end()) - return EmptyActual.end(); - return ii->second.end(); - } - - key_iterator key_begin() const { - return key_iterator(ActualCallees.begin()); - } - - key_iterator key_end() const { - return key_iterator(ActualCallees.end()); - } - - flat_iterator flat_callee_begin(const llvm::Function* F) const { - SimpleCalleesTy::const_iterator ii = SimpleCallees.find(F); - if (ii == SimpleCallees.end()) - return EmptySimple.end(); - return ii->second.begin(); - } - - flat_iterator flat_callee_end(const llvm::Function* F) const { - SimpleCalleesTy::const_iterator ii = SimpleCallees.find(F); - if (ii == SimpleCallees.end()) - return EmptySimple.end(); - return ii->second.end(); - } - - flat_key_iterator flat_key_begin() const { - return flat_key_iterator(SimpleCallees.begin()); - } - - flat_key_iterator flat_key_end() const { - return flat_key_iterator(SimpleCallees.end()); - } - - - unsigned callee_size(llvm::CallSite CS) const { - ActualCalleesTy::const_iterator ii = ActualCallees.find(CS); - if (ii == ActualCallees.end()) - return 0; - return ii->second.size(); - } - - unsigned size() const { - unsigned sum = 0; - for (ActualCalleesTy::const_iterator ii = ActualCallees.begin(), - ee = ActualCallees.end(); ii != ee; ++ii) - sum += ii->second.size(); - return sum; - } - - void clear() { - ActualCallees.clear(); - } - -}; - -class DSSCCGraph { -public: - //SCCs, each element is an SCC - std::map SCCs; - //mapping of functions in SCCs to SCCs index - std::map invmap; - - unsigned nextSCC; - - //Functions we know about that aren't called - svset knownRoots; - - std::map > SCCCallees; - std::map > ExtCallees; - - DSCallGraph oldGraph; - -private: - typedef std::map TFMap; - typedef std::vector TFStack; - - bool hasPointers(const llvm::Function* F) { - if (F->isVarArg()) return true; - if (F->getReturnType()->isPointerTy()) return true; - for (llvm::Function::const_arg_iterator ii = F->arg_begin(), ee = F->arg_end(); - ii != ee; ++ii) - if (ii->getType()->isPointerTy()) return true; - return false; - } - - unsigned tarjan_rec(const llvm::Function* F, TFStack& Stack, unsigned &NextID, - TFMap& ValMap, DSCallGraph& cg) { - assert(!ValMap.count(F) && "Shouldn't revisit functions!"); - unsigned Min = NextID++, MyID = Min; - ValMap[F] = Min; - Stack.push_back(F); - - // The edges out of the current node are the call site targets... - for (DSCallGraph::flat_iterator ii = cg.flat_callee_begin(F), - ee = cg.flat_callee_end(F); ii != ee; ++ii) { - if (hasPointers(*ii) && !(*ii)->isDeclaration()) { - unsigned M = Min; - // Have we visited the destination function yet? - TFMap::iterator It = ValMap.find(*ii); - if (It == ValMap.end()) // No, visit it now. - M = tarjan_rec(*ii, Stack, NextID, ValMap, cg); - else if (std::find(Stack.begin(), Stack.end(), *ii) != Stack.end()) - M = It->second; - if (M < Min) Min = M; - } - } - - assert(ValMap[F] == MyID && "SCC construction assumption wrong!"); - if (Min != MyID) - return Min; // This is part of a larger SCC! - - // If this is a new SCC, process it now. - ++nextSCC; - - const llvm::Function* NF = 0; - do { - NF = Stack.back(); - Stack.pop_back(); - assert(NF && "Null Function"); - assert(invmap.find(NF) == invmap.end() && "Function already in invmap"); - invmap[NF] = nextSCC; - assert(SCCs[nextSCC].find(NF) == SCCs[nextSCC].end() && - "Function already in SCC"); - SCCs[nextSCC].insert(NF); - } while (NF != F); - - return MyID; - } - - void buildSCC(DSCallGraph& DSG) { - TFStack Stack; - TFMap ValMap; - unsigned NextID = 1; - - for (DSCallGraph::flat_key_iterator ii = DSG.flat_key_begin(), - ee = DSG.flat_key_end(); ii != ee; ++ii) - if (!ValMap.count(*ii)) - tarjan_rec(*ii, Stack, NextID, ValMap, DSG); - } - - void buildCallGraph(DSCallGraph& DSG) { - for(DSCallGraph::flat_key_iterator ii = DSG.flat_key_begin(), - ee = DSG.flat_key_end(); ii != ee; ++ii) { - assert (*ii && "Null Function"); - assert(invmap.find(*ii) != invmap.end() && "Unknown Function"); - for (DSCallGraph::flat_iterator fi = DSG.flat_callee_begin(*ii), - fe = DSG.flat_callee_end(*ii); fi != fe; ++fi) { - assert(*fi && "Null Function"); - assert(invmap.find(*fi) != invmap.end() && "Unknown Function"); - if (invmap[*ii] != invmap[*fi]) // No self calls - if (hasPointers(*fi)) { - if ((*fi)->isDeclaration()) - ExtCallees[invmap[*ii]].insert(invmap[*fi]); - else - SCCCallees[invmap[*ii]].insert(invmap[*fi]); - } - } - } - } - - void buildRoots() { - svset knownCallees; - svset knownCallers; - for (std::map >::iterator - ii = SCCCallees.begin(), ee = SCCCallees.end(); ii != ee; ++ii) { - knownCallees.insert(ii->second.begin(), ii->second.end()); - knownCallers.insert(ii->first); - } - for (svset::iterator ii = knownCallers.begin(), - ee = knownCallers.end(); ii != ee; ++ii) - if (!knownCallees.count(*ii)) - knownRoots.insert(*ii); - } - - void assertMapValid() { - for (std::map::iterator ii = SCCs.begin(), - ee = SCCs.end(); ii != ee; ++ii) { - for (DSCallGraph::FuncSet::iterator i = ii->second.begin(), - e = ii->second.end(); i != e; ++i) { - assert(*i && "Null Function in map"); - assert(invmap.find(*i) != invmap.end() && "Function not in invmap"); - assert(invmap[*i] == ii->first && "invmap doesn't match map"); - } - } - - for (std::map::iterator ii = invmap.begin(), - ee = invmap.end(); ii != ee; ++ii) { - assert(ii->first && "Null Function in invmap"); - assert(SCCs.find(ii->second) != SCCs.end() && "Function in invmap but not in map"); - assert(SCCs[ii->second].count(ii->first) && "SCC doesn't contain function"); - } - } - -public: - - DSSCCGraph(DSCallGraph& DSG) :nextSCC(0) { - oldGraph = DSG; - - buildSCC(DSG); - assertMapValid(); - - buildCallGraph(DSG); - - buildRoots(); - - } - - void dump() { - //function map - for (std::map::iterator ii = SCCs.begin(), - ee = SCCs.end(); ii != ee; ++ii) { - llvm::errs() << "Functions in " << ii->first << ":"; - for (DSCallGraph::FuncSet::iterator i = ii->second.begin(), - e = ii->second.end(); i != e; ++i) - llvm::errs() << " " << *i << "(" << invmap[*i] << ")"; - llvm::errs() << "\n"; - } - -// for (std::map::iterator ii = invmap.begin(), -// ee = invmap.end(); ii != ee; ++ii) -// llvm::errs() << ii->first << " -> " << ii->second << "\n"; - - //SCC map - for (std::map >::iterator ii = SCCCallees.begin(), - ee = SCCCallees.end(); ii != ee; ++ii) { - llvm::errs() << "CallGraph[" << ii->first << "]"; - for (svset::iterator i = ii->second.begin(), - e = ii->second.end(); i != e; ++i) - llvm::errs() << " " << *i; - llvm::errs() << "\n"; - } - - //Functions we know about that aren't called - llvm::errs() << "Roots:"; - for (svset::iterator ii = knownRoots.begin(), - ee = knownRoots.end(); ii != ee; ++ii) - llvm::errs() << " " << *ii; - llvm::errs() << "\n"; - } - -}; - -#endif /* LLVM_DSCALLGRAPH_H */ +#endif /* LLVM_KEYITERATOR_H */ From evan.cheng at apple.com Wed Mar 17 11:59:33 2010 From: evan.cheng at apple.com (Evan Cheng) Date: Wed, 17 Mar 2010 09:59:33 -0700 Subject: [llvm-commits] [llvm] r98023 - /llvm/trunk/lib/CodeGen/SimpleRegisterCoalescing.cpp In-Reply-To: References: <20100309005948.483A02A6C12C@llvm.org> <59424131-A98B-428A-9BE7-75786CE199C4@2pi.dk> <8CB245DF-F632-42BA-88C8-46140C3321D6@2pi.dk> <306D339C-D88F-4AE7-B523-B1C6DA2FB219@apple.com> <1643FF41-32A6-41EE-8CA5-3776585ACB74@apple.com> Message-ID: <72A221A7-6881-4AC0-93B9-888CFC6E3FAB@apple.com> On Mar 17, 2010, at 7:25 AM, Jakob Stoklund Olesen wrote: > > On Mar 16, 2010, at 11:19 PM, Evan Cheng wrote: >>> On Mar 16, 2010, at 6:37 PM, Jakob Stoklund Olesen wrote: > >>>> Ideally, I want to avoid physreg joining altogether, and use better hinting instead. Half of the coalescer would go away, and all of the bugs ;-) >> >> That's the proper way to fix this. But we are ready to just do this yet. At least not with the short comings of linear scan. > > Do we know what those shortcomings are? Linearscan just isn't designed to deal with hints effectively. It's top down, which means it has to get lucky to be able to follow the hint. A priority based approach should work better especially for dealing with short intervals with high spill weights. > > My plan is to calculate hints at the same time as spill weights, instead of during coalescing. That allows a weighted vote in case there are multiple physreg copies of the same vreg. (Right now, the vote goes to whatever physreg was seen last.) > > Second, I want to recalculate hints (and possibly spill weights) after breaking up a live interval for spilling. > > In a perfect world, we could eliminate the trivial coalescing pass after register allocation too. I think these are goodness regardless. But disabling physreg / vreg coalescing means the regalloc need to get *every* case we care about right. I am skeptical this is enough given linearscan's design constraint. Evan > > One problem is that linear scan resets the hints when it is backtracking, are there others? > > /jakob > From jyasskin at google.com Wed Mar 17 12:04:56 2010 From: jyasskin at google.com (Jeffrey Yasskin) Date: Wed, 17 Mar 2010 17:04:56 -0000 Subject: [llvm-commits] [llvm] r98741 - /llvm/trunk/utils/lit/lit/TestRunner.py Message-ID: <20100317170456.352AA2A6C12C@llvm.org> Author: jyasskin Date: Wed Mar 17 12:04:56 2010 New Revision: 98741 URL: http://llvm.org/viewvc/llvm-project?rev=98741&view=rev Log: Make lit pay attention to --vg for tcl tests too, which makes it work on LLVM's non-unit tests. Modified: llvm/trunk/utils/lit/lit/TestRunner.py Modified: llvm/trunk/utils/lit/lit/TestRunner.py URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/utils/lit/lit/TestRunner.py?rev=98741&r1=98740&r2=98741&view=diff ============================================================================== --- llvm/trunk/utils/lit/lit/TestRunner.py (original) +++ llvm/trunk/utils/lit/lit/TestRunner.py Wed Mar 17 12:04:56 2010 @@ -252,6 +252,18 @@ except: return (Test.FAIL, "Tcl 'exec' parse error on: %r" % ln) + if litConfig.useValgrind: + valgrindArgs = ['valgrind', '-q', + '--tool=memcheck', '--trace-children=yes', + '--error-exitcode=123'] + valgrindArgs.extend(litConfig.valgrindArgs) + for pipeline in cmds: + if pipeline.commands: + # Only valgrind the first command in each pipeline, to avoid + # valgrinding things like grep, not, and FileCheck. + cmd = pipeline.commands[0] + cmd.args = valgrindArgs + cmd.args + cmd = cmds[0] for c in cmds[1:]: cmd = ShUtil.Seq(cmd, '&&', c) From stuart at apple.com Wed Mar 17 12:06:24 2010 From: stuart at apple.com (Stuart Hastings) Date: Wed, 17 Mar 2010 10:06:24 -0700 Subject: [llvm-commits] [llvm-gcc-4.2] r98728 - /llvm-gcc-4.2/trunk/gcc/llvm-convert.cpp In-Reply-To: <00A80928-1795-4EBC-BA54-F7D8E1BB3A36@apple.com> References: <20100317155915.205E22A6C12C@llvm.org> <00A80928-1795-4EBC-BA54-F7D8E1BB3A36@apple.com> Message-ID: On Mar 17, 2010, at 9:37 AM, Chris Lattner wrote: > testcase? Working on it. stuart > On Mar 17, 2010, at 8:59 AM, Stuart Hastings wrote: > >> Author: stuart >> Date: Wed Mar 17 10:59:14 2010 >> New Revision: 98728 >> >> URL: http://llvm.org/viewvc/llvm-project?rev=98728&view=rev >> Log: >> Use GCC-specd type when referencing ObjC2 bitfields. Radar 7639995. >> >> Modified: >> llvm-gcc-4.2/trunk/gcc/llvm-convert.cpp >> >> Modified: llvm-gcc-4.2/trunk/gcc/llvm-convert.cpp >> URL: http://llvm.org/viewvc/llvm-project/llvm-gcc-4.2/trunk/gcc/llvm-convert.cpp?rev=98728&r1=98727&r2=98728&view=diff >> ============================================================================== >> --- llvm-gcc-4.2/trunk/gcc/llvm-convert.cpp (original) >> +++ llvm-gcc-4.2/trunk/gcc/llvm-convert.cpp Wed Mar 17 10:59:14 2010 >> @@ -7021,6 +7021,11 @@ >> LVAlign = MinAlign(LVAlign, ByteOffset); >> } >> >> + // Since we're using GCC's offset, we're obliged to use GCC's >> + // "shrink-wrapped" type for the reference, lest we reference >> + // memory outside of this struct. >> + FieldTy = ConvertType(TREE_TYPE(FieldDecl)); >> + >> Value *Ptr = CastToType(Instruction::PtrToInt, StructAddrLV.Ptr, >> Offset->getType()); >> Ptr = Builder.CreateAdd(Ptr, Offset); >> >> >> _______________________________________________ >> llvm-commits mailing list >> llvm-commits at cs.uiuc.edu >> http://lists.cs.uiuc.edu/mailman/listinfo/llvm-commits > From johnny.chen at apple.com Wed Mar 17 12:10:35 2010 From: johnny.chen at apple.com (Johnny Chen) Date: Wed, 17 Mar 2010 10:10:35 -0700 Subject: [llvm-commits] [llvm] r98679 - in /llvm/trunk/lib/Target/ARM: ARMInstrInfo.td ARMInstrVFP.td In-Reply-To: <238CF4E8-13D1-4ACB-AEB9-221C7C2FDEF7@apple.com> References: <20100316212506.1176A2A6C12C@llvm.org> <238CF4E8-13D1-4ACB-AEB9-221C7C2FDEF7@apple.com> Message-ID: <274E1015-3F04-4720-B188-00E0B6728FCF@apple.com> Specifying the encoding bit (Inst{21} = 1) helps the decoder which is mostly based on the well-known encoding bits of instructions. Can I keep it in? On Mar 17, 2010, at 8:46 AM, Bob Wilson wrote: > These variants are already distinguished by IndexModeNone vs. IndexModeUpd. Can you use that distinction to determine the writeback bit? > > On Mar 16, 2010, at 2:25 PM, Johnny Chen wrote: > >> Author: johnny >> Date: Tue Mar 16 16:25:05 2010 >> New Revision: 98679 >> >> URL: http://llvm.org/viewvc/llvm-project?rev=98679&view=rev >> Log: >> Disambiguate the *_UPD and * variants by specifying the writeback flag as 1. >> This is for the disassembly work. >> >> There are cases where this is not possible, for example, A8.6.53 LDM Encoding T1. >> In such case, we'll use an adhoc approach to deduce the Opcode programmatically. >> >> Modified: >> llvm/trunk/lib/Target/ARM/ARMInstrInfo.td >> llvm/trunk/lib/Target/ARM/ARMInstrVFP.td >> >> Modified: llvm/trunk/lib/Target/ARM/ARMInstrInfo.td >> URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Target/ARM/ARMInstrInfo.td?rev=98679&r1=98678&r2=98679&view=diff >> ============================================================================== >> --- llvm/trunk/lib/Target/ARM/ARMInstrInfo.td (original) >> +++ llvm/trunk/lib/Target/ARM/ARMInstrInfo.td Tue Mar 16 16:25:05 2010 >> @@ -1355,7 +1355,9 @@ >> reglist:$dsts, variable_ops), >> IndexModeUpd, LdStMulFrm, IIC_iLoadm, >> "ldm${addr:submode}${p}\t$addr!, $dsts", >> - "$addr.addr = $wb", []>; >> + "$addr.addr = $wb", []> { >> + let Inst{21} = 1; // wback >> +} >> } // mayLoad, hasExtraDefRegAllocReq >> >> let mayStore = 1, hasExtraSrcRegAllocReq = 1 in { >> @@ -1368,7 +1370,9 @@ >> reglist:$srcs, variable_ops), >> IndexModeUpd, LdStMulFrm, IIC_iStorem, >> "stm${addr:submode}${p}\t$addr!, $srcs", >> - "$addr.addr = $wb", []>; >> + "$addr.addr = $wb", []> { >> + let Inst{21} = 1; // wback >> +} >> } // mayStore, hasExtraSrcRegAllocReq >> >> //===----------------------------------------------------------------------===// >> >> Modified: llvm/trunk/lib/Target/ARM/ARMInstrVFP.td >> URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Target/ARM/ARMInstrVFP.td?rev=98679&r1=98678&r2=98679&view=diff >> ============================================================================== >> --- llvm/trunk/lib/Target/ARM/ARMInstrVFP.td (original) >> +++ llvm/trunk/lib/Target/ARM/ARMInstrVFP.td Tue Mar 16 16:25:05 2010 >> @@ -96,6 +96,7 @@ >> IndexModeUpd, IIC_fpLoadm, >> "vldm${addr:submode}${p}\t${addr:base}!, $dsts", >> "$addr.base = $wb", []> { >> + let Inst{21} = 1; // wback >> let Inst{20} = 1; >> } >> >> @@ -104,6 +105,7 @@ >> IndexModeUpd, IIC_fpLoadm, >> "vldm${addr:submode}${p}\t${addr:base}!, $dsts", >> "$addr.base = $wb", []> { >> + let Inst{21} = 1; // wback >> let Inst{20} = 1; >> } >> } // mayLoad, hasExtraDefRegAllocReq >> @@ -126,6 +128,7 @@ >> IndexModeUpd, IIC_fpStorem, >> "vstm${addr:submode}${p}\t${addr:base}!, $srcs", >> "$addr.base = $wb", []> { >> + let Inst{21} = 1; // wback >> let Inst{20} = 0; >> } >> >> @@ -134,6 +137,7 @@ >> IndexModeUpd, IIC_fpStorem, >> "vstm${addr:submode}${p}\t${addr:base}!, $srcs", >> "$addr.base = $wb", []> { >> + let Inst{21} = 1; // wback >> let Inst{20} = 0; >> } >> } // mayStore, hasExtraSrcRegAllocReq >> >> >> _______________________________________________ >> llvm-commits mailing list >> llvm-commits at cs.uiuc.edu >> http://lists.cs.uiuc.edu/mailman/listinfo/llvm-commits > From sabre at nondot.org Wed Mar 17 12:25:49 2010 From: sabre at nondot.org (Chris Lattner) Date: Wed, 17 Mar 2010 17:25:49 -0000 Subject: [llvm-commits] [llvm] r98742 - /llvm/trunk/docs/ReleaseNotes.html Message-ID: <20100317172549.55E822A6C12C@llvm.org> Author: lattner Date: Wed Mar 17 12:25:49 2010 New Revision: 98742 URL: http://llvm.org/viewvc/llvm-project?rev=98742&view=rev Log: several updates Modified: llvm/trunk/docs/ReleaseNotes.html Modified: llvm/trunk/docs/ReleaseNotes.html URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/docs/ReleaseNotes.html?rev=98742&r1=98741&r2=98742&view=diff ============================================================================== --- llvm/trunk/docs/ReleaseNotes.html (original) +++ llvm/trunk/docs/ReleaseNotes.html Wed Mar 17 12:25:49 2010 @@ -310,8 +310,6 @@

    -Need update. -

    +

    Pure versions 0.43 and later have been tested and are known to work with +LLVM 2.7 (and continue to work with older LLVM releases >= 2.5).

    +
    @@ -354,13 +352,11 @@

    -Need update. -

    +

    @@ -767,13 +763,7 @@ href="http://llvm.org/bugs/">LLVM bug database and submit a bug if there isn't already one.

    -
      -
    • The llvm-gcc bootstrap will fail with some versions of binutils (e.g. 2.15) - with a message of "Error: can not do 8 - byte pc-relative relocation" when building C++ code. We intend to - fix this on mainline, but a workaround is to upgrade to binutils 2.17 or - later.
    • - +
      • LLVM will not correctly compile on Solaris and/or OpenSolaris using the stock GCC 3.x.x series 'out the box', See: Broken versions of GCC and other tools. From dpatel at apple.com Wed Mar 17 12:29:55 2010 From: dpatel at apple.com (Devang Patel) Date: Wed, 17 Mar 2010 17:29:55 -0000 Subject: [llvm-commits] [llvm] r98743 - /llvm/trunk/lib/CodeGen/AsmPrinter/DwarfDebug.cpp Message-ID: <20100317172955.D21B92A6C12C@llvm.org> Author: dpatel Date: Wed Mar 17 12:29:55 2010 New Revision: 98743 URL: http://llvm.org/viewvc/llvm-project?rev=98743&view=rev Log: Fix EmitSectionOffset incorrect argument. DwarfDebug is emitting debug info so isEH is always false. This was hiding until now from compilers because of default arguments. This was hiding from dwarf debug info users because for most of the platform isAbsoluteEHSectionOffsets() is same as isAbsoluteDebugSectionOffsets(). But Chris found it while updating dwarf printer to use MC*. Modified: llvm/trunk/lib/CodeGen/AsmPrinter/DwarfDebug.cpp Modified: llvm/trunk/lib/CodeGen/AsmPrinter/DwarfDebug.cpp URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/CodeGen/AsmPrinter/DwarfDebug.cpp?rev=98743&r1=98742&r2=98743&view=diff ============================================================================== --- llvm/trunk/lib/CodeGen/AsmPrinter/DwarfDebug.cpp (original) +++ llvm/trunk/lib/CodeGen/AsmPrinter/DwarfDebug.cpp Wed Mar 17 12:29:55 2010 @@ -2531,8 +2531,8 @@ Asm->OutStreamer.AddComment("DWARF version number"); Asm->EmitInt16(dwarf::DWARF_VERSION); Asm->OutStreamer.AddComment("Offset Into Abbrev. Section"); - EmitSectionOffset(getTempLabel("abbrev_begin"),getTempLabel("section_abbrev"), - true, false); + EmitSectionOffset(getTempLabel("abbrev_begin"),getTempLabel("section_abbrev"), + true); Asm->OutStreamer.AddComment("Address Size (in bytes)"); Asm->EmitInt8(TD->getPointerSize()); @@ -2842,8 +2842,8 @@ Asm->OutStreamer.EmitLabel(DebugFrameBegin); Asm->OutStreamer.AddComment("FDE CIE offset"); - EmitSectionOffset(getTempLabel("debug_frame_common"), - getTempLabel("section_debug_frame"), true, false); + EmitSectionOffset(getTempLabel("debug_frame_common"), + getTempLabel("section_debug_frame"), true); Asm->OutStreamer.AddComment("FDE initial location"); MCSymbol *FuncBeginSym = getDWLabel("func_begin", DebugFrameInfo.Number); @@ -2878,8 +2878,7 @@ Asm->OutStreamer.AddComment("Offset of Compilation Unit Info"); EmitSectionOffset(getDWLabel("info_begin", ModuleCU->getID()), - getTempLabel("section_info"), - true, false); + getTempLabel("section_info"), true); Asm->OutStreamer.AddComment("Compilation Unit Length"); EmitDifference(getDWLabel("info_end", ModuleCU->getID()), @@ -2920,7 +2919,7 @@ Asm->OutStreamer.AddComment("Offset of Compilation ModuleCU Info"); EmitSectionOffset(getDWLabel("info_begin", ModuleCU->getID()), - getTempLabel("section_info"), true, false); + getTempLabel("section_info"), true); Asm->OutStreamer.AddComment("Compilation ModuleCU Length"); EmitDifference(getDWLabel("info_end", ModuleCU->getID()), @@ -3068,8 +3067,8 @@ getTempLabel("section_str"), true); Asm->OutStreamer.AddComment("Function name"); - EmitSectionOffset(getStringPoolEntry(Name), getTempLabel("section_str"), - false, true); + EmitSectionOffset(getStringPoolEntry(Name), getTempLabel("section_str"), + true); EmitULEB128(Labels.size(), "Inline count"); for (SmallVector::iterator LI = Labels.begin(), From bob.wilson at apple.com Wed Mar 17 12:43:12 2010 From: bob.wilson at apple.com (Bob Wilson) Date: Wed, 17 Mar 2010 10:43:12 -0700 Subject: [llvm-commits] [llvm] r98679 - in /llvm/trunk/lib/Target/ARM: ARMInstrInfo.td ARMInstrVFP.td In-Reply-To: <274E1015-3F04-4720-B188-00E0B6728FCF@apple.com> References: <20100316212506.1176A2A6C12C@llvm.org> <238CF4E8-13D1-4ACB-AEB9-221C7C2FDEF7@apple.com> <274E1015-3F04-4720-B188-00E0B6728FCF@apple.com> Message-ID: <9EBDCD7F-C95D-445E-9C5F-2C72A674F324@apple.com> On Mar 17, 2010, at 10:10 AM, Johnny Chen wrote: > Specifying the encoding bit (Inst{21} = 1) helps the decoder which is mostly > based on the well-known encoding bits of instructions. Can I keep it in? Well, you can if that's really the best solution.... As you've been working on the disassembler, we've been getting more and more of these extra assignments for instruction encodings. At some point, they become an obstacle to readability in the .td files. For the JIT encoder, there are some bits that are set programmatically based on the instruction formats, so that the .td file can specify the format and the individual bits are set elsewhere based on the format. Unless there is a fundamental reason why that approach can't be used for the disassembler, it seems to me like a much better design. > > On Mar 17, 2010, at 8:46 AM, Bob Wilson wrote: > >> These variants are already distinguished by IndexModeNone vs. IndexModeUpd. Can you use that distinction to determine the writeback bit? >> >> On Mar 16, 2010, at 2:25 PM, Johnny Chen wrote: >> >>> Author: johnny >>> Date: Tue Mar 16 16:25:05 2010 >>> New Revision: 98679 >>> >>> URL: http://llvm.org/viewvc/llvm-project?rev=98679&view=rev >>> Log: >>> Disambiguate the *_UPD and * variants by specifying the writeback flag as 1. >>> This is for the disassembly work. >>> >>> There are cases where this is not possible, for example, A8.6.53 LDM Encoding T1. >>> In such case, we'll use an adhoc approach to deduce the Opcode programmatically. >>> >>> Modified: >>> llvm/trunk/lib/Target/ARM/ARMInstrInfo.td >>> llvm/trunk/lib/Target/ARM/ARMInstrVFP.td >>> >>> Modified: llvm/trunk/lib/Target/ARM/ARMInstrInfo.td >>> URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Target/ARM/ARMInstrInfo.td?rev=98679&r1=98678&r2=98679&view=diff >>> ============================================================================== >>> --- llvm/trunk/lib/Target/ARM/ARMInstrInfo.td (original) >>> +++ llvm/trunk/lib/Target/ARM/ARMInstrInfo.td Tue Mar 16 16:25:05 2010 >>> @@ -1355,7 +1355,9 @@ >>> reglist:$dsts, variable_ops), >>> IndexModeUpd, LdStMulFrm, IIC_iLoadm, >>> "ldm${addr:submode}${p}\t$addr!, $dsts", >>> - "$addr.addr = $wb", []>; >>> + "$addr.addr = $wb", []> { >>> + let Inst{21} = 1; // wback >>> +} >>> } // mayLoad, hasExtraDefRegAllocReq >>> >>> let mayStore = 1, hasExtraSrcRegAllocReq = 1 in { >>> @@ -1368,7 +1370,9 @@ >>> reglist:$srcs, variable_ops), >>> IndexModeUpd, LdStMulFrm, IIC_iStorem, >>> "stm${addr:submode}${p}\t$addr!, $srcs", >>> - "$addr.addr = $wb", []>; >>> + "$addr.addr = $wb", []> { >>> + let Inst{21} = 1; // wback >>> +} >>> } // mayStore, hasExtraSrcRegAllocReq >>> >>> //===----------------------------------------------------------------------===// >>> >>> Modified: llvm/trunk/lib/Target/ARM/ARMInstrVFP.td >>> URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Target/ARM/ARMInstrVFP.td?rev=98679&r1=98678&r2=98679&view=diff >>> ============================================================================== >>> --- llvm/trunk/lib/Target/ARM/ARMInstrVFP.td (original) >>> +++ llvm/trunk/lib/Target/ARM/ARMInstrVFP.td Tue Mar 16 16:25:05 2010 >>> @@ -96,6 +96,7 @@ >>> IndexModeUpd, IIC_fpLoadm, >>> "vldm${addr:submode}${p}\t${addr:base}!, $dsts", >>> "$addr.base = $wb", []> { >>> + let Inst{21} = 1; // wback >>> let Inst{20} = 1; >>> } >>> >>> @@ -104,6 +105,7 @@ >>> IndexModeUpd, IIC_fpLoadm, >>> "vldm${addr:submode}${p}\t${addr:base}!, $dsts", >>> "$addr.base = $wb", []> { >>> + let Inst{21} = 1; // wback >>> let Inst{20} = 1; >>> } >>> } // mayLoad, hasExtraDefRegAllocReq >>> @@ -126,6 +128,7 @@ >>> IndexModeUpd, IIC_fpStorem, >>> "vstm${addr:submode}${p}\t${addr:base}!, $srcs", >>> "$addr.base = $wb", []> { >>> + let Inst{21} = 1; // wback >>> let Inst{20} = 0; >>> } >>> >>> @@ -134,6 +137,7 @@ >>> IndexModeUpd, IIC_fpStorem, >>> "vstm${addr:submode}${p}\t${addr:base}!, $srcs", >>> "$addr.base = $wb", []> { >>> + let Inst{21} = 1; // wback >>> let Inst{20} = 0; >>> } >>> } // mayStore, hasExtraSrcRegAllocReq >>> >>> >>> _______________________________________________ >>> llvm-commits mailing list >>> llvm-commits at cs.uiuc.edu >>> http://lists.cs.uiuc.edu/mailman/listinfo/llvm-commits >> > From johnny.chen at apple.com Wed Mar 17 12:49:24 2010 From: johnny.chen at apple.com (Johnny Chen) Date: Wed, 17 Mar 2010 10:49:24 -0700 Subject: [llvm-commits] [llvm] r98679 - in /llvm/trunk/lib/Target/ARM: ARMInstrInfo.td ARMInstrVFP.td In-Reply-To: <9EBDCD7F-C95D-445E-9C5F-2C72A674F324@apple.com> References: <20100316212506.1176A2A6C12C@llvm.org> <238CF4E8-13D1-4ACB-AEB9-221C7C2FDEF7@apple.com> <274E1015-3F04-4720-B188-00E0B6728FCF@apple.com> <9EBDCD7F-C95D-445E-9C5F-2C72A674F324@apple.com> Message-ID: <2AEC5D10-96C0-422A-AE3C-ED6B0B123868@apple.com> The JIT encoder knows it is working with a certain instruction in the instruction table. It known the Opcode, as well as other attributes. The decoder has no idea what the raw bits represent, it has to work its way to find the rightful owner of the raw bits. On Mar 17, 2010, at 10:43 AM, Bob Wilson wrote: > On Mar 17, 2010, at 10:10 AM, Johnny Chen wrote: > >> Specifying the encoding bit (Inst{21} = 1) helps the decoder which is mostly >> based on the well-known encoding bits of instructions. Can I keep it in? > > Well, you can if that's really the best solution.... As you've been working on the disassembler, we've been getting more and more of these extra assignments for instruction encodings. At some point, they become an obstacle to readability in the .td files. > > For the JIT encoder, there are some bits that are set programmatically based on the instruction formats, so that the .td file can specify the format and the individual bits are set elsewhere based on the format. Unless there is a fundamental reason why that approach can't be used for the disassembler, it seems to me like a much better design. > >> >> On Mar 17, 2010, at 8:46 AM, Bob Wilson wrote: >> >>> These variants are already distinguished by IndexModeNone vs. IndexModeUpd. Can you use that distinction to determine the writeback bit? >>> >>> On Mar 16, 2010, at 2:25 PM, Johnny Chen wrote: >>> >>>> Author: johnny >>>> Date: Tue Mar 16 16:25:05 2010 >>>> New Revision: 98679 >>>> >>>> URL: http://llvm.org/viewvc/llvm-project?rev=98679&view=rev >>>> Log: >>>> Disambiguate the *_UPD and * variants by specifying the writeback flag as 1. >>>> This is for the disassembly work. >>>> >>>> There are cases where this is not possible, for example, A8.6.53 LDM Encoding T1. >>>> In such case, we'll use an adhoc approach to deduce the Opcode programmatically. >>>> >>>> Modified: >>>> llvm/trunk/lib/Target/ARM/ARMInstrInfo.td >>>> llvm/trunk/lib/Target/ARM/ARMInstrVFP.td >>>> >>>> Modified: llvm/trunk/lib/Target/ARM/ARMInstrInfo.td >>>> URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Target/ARM/ARMInstrInfo.td?rev=98679&r1=98678&r2=98679&view=diff >>>> ============================================================================== >>>> --- llvm/trunk/lib/Target/ARM/ARMInstrInfo.td (original) >>>> +++ llvm/trunk/lib/Target/ARM/ARMInstrInfo.td Tue Mar 16 16:25:05 2010 >>>> @@ -1355,7 +1355,9 @@ >>>> reglist:$dsts, variable_ops), >>>> IndexModeUpd, LdStMulFrm, IIC_iLoadm, >>>> "ldm${addr:submode}${p}\t$addr!, $dsts", >>>> - "$addr.addr = $wb", []>; >>>> + "$addr.addr = $wb", []> { >>>> + let Inst{21} = 1; // wback >>>> +} >>>> } // mayLoad, hasExtraDefRegAllocReq >>>> >>>> let mayStore = 1, hasExtraSrcRegAllocReq = 1 in { >>>> @@ -1368,7 +1370,9 @@ >>>> reglist:$srcs, variable_ops), >>>> IndexModeUpd, LdStMulFrm, IIC_iStorem, >>>> "stm${addr:submode}${p}\t$addr!, $srcs", >>>> - "$addr.addr = $wb", []>; >>>> + "$addr.addr = $wb", []> { >>>> + let Inst{21} = 1; // wback >>>> +} >>>> } // mayStore, hasExtraSrcRegAllocReq >>>> >>>> //===----------------------------------------------------------------------===// >>>> >>>> Modified: llvm/trunk/lib/Target/ARM/ARMInstrVFP.td >>>> URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Target/ARM/ARMInstrVFP.td?rev=98679&r1=98678&r2=98679&view=diff >>>> ============================================================================== >>>> --- llvm/trunk/lib/Target/ARM/ARMInstrVFP.td (original) >>>> +++ llvm/trunk/lib/Target/ARM/ARMInstrVFP.td Tue Mar 16 16:25:05 2010 >>>> @@ -96,6 +96,7 @@ >>>> IndexModeUpd, IIC_fpLoadm, >>>> "vldm${addr:submode}${p}\t${addr:base}!, $dsts", >>>> "$addr.base = $wb", []> { >>>> + let Inst{21} = 1; // wback >>>> let Inst{20} = 1; >>>> } >>>> >>>> @@ -104,6 +105,7 @@ >>>> IndexModeUpd, IIC_fpLoadm, >>>> "vldm${addr:submode}${p}\t${addr:base}!, $dsts", >>>> "$addr.base = $wb", []> { >>>> + let Inst{21} = 1; // wback >>>> let Inst{20} = 1; >>>> } >>>> } // mayLoad, hasExtraDefRegAllocReq >>>> @@ -126,6 +128,7 @@ >>>> IndexModeUpd, IIC_fpStorem, >>>> "vstm${addr:submode}${p}\t${addr:base}!, $srcs", >>>> "$addr.base = $wb", []> { >>>> + let Inst{21} = 1; // wback >>>> let Inst{20} = 0; >>>> } >>>> >>>> @@ -134,6 +137,7 @@ >>>> IndexModeUpd, IIC_fpStorem, >>>> "vstm${addr:submode}${p}\t${addr:base}!, $srcs", >>>> "$addr.base = $wb", []> { >>>> + let Inst{21} = 1; // wback >>>> let Inst{20} = 0; >>>> } >>>> } // mayStore, hasExtraSrcRegAllocReq >>>> >>>> >>>> _______________________________________________ >>>> llvm-commits mailing list >>>> llvm-commits at cs.uiuc.edu >>>> http://lists.cs.uiuc.edu/mailman/listinfo/llvm-commits >>> >> > From stuart at apple.com Wed Mar 17 12:51:08 2010 From: stuart at apple.com (Stuart Hastings) Date: Wed, 17 Mar 2010 17:51:08 -0000 Subject: [llvm-commits] [llvm] r98744 - /llvm/trunk/test/FrontendObjC/2010-03-17-StructRef.m Message-ID: <20100317175108.DF30D2A6C12C@llvm.org> Author: stuart Date: Wed Mar 17 12:51:08 2010 New Revision: 98744 URL: http://llvm.org/viewvc/llvm-project?rev=98744&view=rev Log: Testcase for r98728. Added: llvm/trunk/test/FrontendObjC/2010-03-17-StructRef.m Added: llvm/trunk/test/FrontendObjC/2010-03-17-StructRef.m URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/FrontendObjC/2010-03-17-StructRef.m?rev=98744&view=auto ============================================================================== --- llvm/trunk/test/FrontendObjC/2010-03-17-StructRef.m (added) +++ llvm/trunk/test/FrontendObjC/2010-03-17-StructRef.m Wed Mar 17 12:51:08 2010 @@ -0,0 +1,43 @@ +// RUN: %llvmgcc %s -S -o - | FileCheck %s +// Bitfield references must not touch memory outside of the enclosing +// struct. Radar 7639995 +typedef signed char BOOL; + at protocol NSObject +- (id)init; + at end + at interface NSObject {} + at end + at interface IMAVChatParticipant : NSObject { + int _ardRole; + int _state; + int _avRelayStatus; + int _chatEndedReason; + int _chatError; + unsigned _sendingAudio:1; + unsigned _sendingVideo:1; + unsigned _sendingAuxVideo:1; + unsigned _audioMuted:1; + unsigned _videoPaused:1; + unsigned _networkStalled:1; + unsigned _isInitiator:1; + unsigned _isAOLInterop:1; + unsigned _isRecording:1; + unsigned _isUsingICE:1; +} + at end + at implementation IMAVChatParticipant +- (id) init { + self = [super init]; + if ( self ) { + BOOL blah = (BOOL)1; + // We're expecting these three bitfield assignments will generate i8 stores. + _sendingAudio = (BOOL)1; + _isUsingICE = (BOOL)1; + _isUsingICE = blah; + // CHECK: store i8 + // CHECK: store i8 + // CHECK: store i8 + } + return self; +} + at end From johnny.chen at apple.com Wed Mar 17 12:52:21 2010 From: johnny.chen at apple.com (Johnny Chen) Date: Wed, 17 Mar 2010 17:52:21 -0000 Subject: [llvm-commits] [llvm] r98745 - in /llvm/trunk: lib/Target/ARM/ lib/Target/ARM/AsmPrinter/ test/CodeGen/ARM/ test/CodeGen/Thumb2/ Message-ID: <20100317175221.D9A732A6C12C@llvm.org> Author: johnny Date: Wed Mar 17 12:52:21 2010 New Revision: 98745 URL: http://llvm.org/viewvc/llvm-project?rev=98745&view=rev Log: Added sub-formats to the NeonI/NeonXI instructions to further refine the NEONFrm instructions to help disassembly. We also changed the output of the addressing modes to omit the '+' from the assembler syntax #+/- or +/-. See, for example, A8.6.57/58/60. And modified test cases to not expect '+' in +reg or #+num. For example, ; CHECK: ldr.w r9, [r7, #28] Modified: llvm/trunk/lib/Target/ARM/ARMAddressingModes.h llvm/trunk/lib/Target/ARM/ARMInstrFormats.td llvm/trunk/lib/Target/ARM/ARMInstrNEON.td llvm/trunk/lib/Target/ARM/AsmPrinter/ARMAsmPrinter.cpp llvm/trunk/lib/Target/ARM/AsmPrinter/ARMInstPrinter.cpp llvm/trunk/lib/Target/ARM/AsmPrinter/ARMInstPrinter.h llvm/trunk/test/CodeGen/ARM/2009-10-27-double-align.ll llvm/trunk/test/CodeGen/ARM/2009-10-30.ll llvm/trunk/test/CodeGen/ARM/arm-negative-stride.ll llvm/trunk/test/CodeGen/ARM/globals.ll llvm/trunk/test/CodeGen/ARM/ldrd.ll llvm/trunk/test/CodeGen/ARM/str_pre-2.ll llvm/trunk/test/CodeGen/ARM/tls2.ll llvm/trunk/test/CodeGen/Thumb2/ldr-str-imm12.ll llvm/trunk/test/CodeGen/Thumb2/thumb2-ldr.ll llvm/trunk/test/CodeGen/Thumb2/thumb2-ldrh.ll llvm/trunk/test/CodeGen/Thumb2/thumb2-str.ll llvm/trunk/test/CodeGen/Thumb2/thumb2-str_pre.ll llvm/trunk/test/CodeGen/Thumb2/thumb2-strb.ll llvm/trunk/test/CodeGen/Thumb2/thumb2-strh.ll Modified: llvm/trunk/lib/Target/ARM/ARMAddressingModes.h URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Target/ARM/ARMAddressingModes.h?rev=98745&r1=98744&r2=98745&view=diff ============================================================================== --- llvm/trunk/lib/Target/ARM/ARMAddressingModes.h (original) +++ llvm/trunk/lib/Target/ARM/ARMAddressingModes.h Wed Mar 17 12:52:21 2010 @@ -35,6 +35,10 @@ add = '+', sub = '-' }; + static inline const char *getAddrOpcStr(AddrOpc Op) { + return Op == sub ? "-" : ""; + } + static inline const char *getShiftOpcStr(ShiftOpc Op) { switch (Op) { default: assert(0 && "Unknown shift opc!"); @@ -127,6 +131,20 @@ return (Imm >> 8) * 2; } + /// getSOImmValOneRotate - Try to handle Imm with an immediate shifter + /// operand, computing the rotate amount to use. If this immediate value + /// cannot be handled with a single shifter-op, return 0. + static inline unsigned getSOImmValOneRotate(unsigned Imm) { + // A5.2.4 Constants with multiple encodings + // The lowest unsigned value of rotation wins! + for (unsigned R = 1; R <= 15; ++R) + if ((Imm & rotr32(~255U, 2*R)) == 0) + return 2*R; + + // Failed to find a suitable rotate amount. + return 0; + } + /// getSOImmValRotate - Try to handle Imm with an immediate shifter operand, /// computing the rotate amount to use. If this immediate value cannot be /// handled with a single shifter-op, determine a good rotate amount that will @@ -179,7 +197,7 @@ // of zero. if ((Arg & ~255U) == 0) return Arg; - unsigned RotAmt = getSOImmValRotate(Arg); + unsigned RotAmt = getSOImmValOneRotate(Arg); // If this cannot be handled with a single shifter_op, bail out. if (rotr32(~255U, RotAmt) & Arg) Modified: llvm/trunk/lib/Target/ARM/ARMInstrFormats.td URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Target/ARM/ARMInstrFormats.td?rev=98745&r1=98744&r2=98745&view=diff ============================================================================== --- llvm/trunk/lib/Target/ARM/ARMInstrFormats.td (original) +++ llvm/trunk/lib/Target/ARM/ARMInstrFormats.td Wed Mar 17 12:52:21 2010 @@ -1464,6 +1464,29 @@ // ARM NEON Instruction templates. // +// NSFormat specifies further details of a NEON instruction. This is used by +// the disassembler to classify NEONFrm instructions for disassembly purpose. +class NSFormat val> { + bits<5> Value = val; +} +def NSFormatNone : NSFormat<0>; +def VLDSTLaneFrm : NSFormat<1>; +def VLDSTLaneDblFrm : NSFormat<2>; +def VLDSTRQFrm : NSFormat<3>; +def NVdImmFrm : NSFormat<4>; +def NVdVmImmFrm : NSFormat<5>; +def NVdVmImmVCVTFrm : NSFormat<6>; +def NVdVmImmVDupLaneFrm : NSFormat<7>; +def NVdVmImmVSHLLFrm : NSFormat<8>; +def NVectorShuffleFrm : NSFormat<9>; +def NVectorShiftFrm : NSFormat<10>; +def NVectorShift2Frm : NSFormat<11>; +def NVdVnVmImmFrm : NSFormat<12>; +def NVdVnVmImmVectorShiftFrm : NSFormat<13>; +def NVdVnVmImmVectorExtractFrm : NSFormat<14>; +def NVdVnVmImmMulScalarFrm : NSFormat<15>; +def VTBLFrm : NSFormat<16>; + class NeonI pattern> : InstARM { @@ -1474,6 +1497,8 @@ !strconcat("\t", asm)); let Pattern = pattern; list Predicates = [HasNEON]; + NSFormat NSF = NSFormatNone; // For disassembly. + bits<5> NSForm = NSFormatNone.Value; // For disassembly. } // Same as NeonI except it does not have a "data type" specifier. @@ -1485,6 +1510,8 @@ let AsmString = !strconcat(!strconcat(opc, "${p}"), !strconcat("\t", asm)); let Pattern = pattern; list Predicates = [HasNEON]; + NSFormat NSF = NSFormatNone; // For disassembly. + bits<5> NSForm = NSFormatNone.Value; // For disassembly. } class NI pattern> : NeonXI { + let NSF = VLDSTRQFrm; // For disassembly. + let NSForm = VLDSTRQFrm.Value; // For disassembly. } class NLdSt op21_20, bits<4> op11_8, bits<4> op7_4, @@ -1509,6 +1538,8 @@ let Inst{21-20} = op21_20; let Inst{11-8} = op11_8; let Inst{7-4} = op7_4; + let NSF = VLDSTLaneFrm; // For disassembly. + let NSForm = VLDSTLaneFrm.Value; // For disassembly. } class NDataI op7_4, string OpcodeStr, string Dt> : NLdSt<0,0b10,0b1001,op7_4, (outs DPR:$dst1, DPR:$dst2), (ins addrmode6:$addr), IIC_VLD2, - OpcodeStr, Dt, "\\{$dst1, $dst2\\}, $addr", "", []>; + OpcodeStr, Dt, "\\{$dst1, $dst2\\}, $addr", "", []> { + let NSF = VLDSTLaneDblFrm; // For disassembly. + let NSForm = VLDSTLaneDblFrm.Value; // For disassembly. +} def VLD2d8D : VLD2Ddbl<0b0000, "vld2", "8">; def VLD2d16D : VLD2Ddbl<0b0100, "vld2", "16">; @@ -228,7 +231,10 @@ : NLdSt<0,0b10,0b0101,op7_4, (outs DPR:$dst1, DPR:$dst2, DPR:$dst3, GPR:$wb), (ins addrmode6:$addr), IIC_VLD3, OpcodeStr, Dt, "\\{$dst1, $dst2, $dst3\\}, $addr", - "$addr.addr = $wb", []>; + "$addr.addr = $wb", []> { + let NSF = VLDSTLaneDblFrm; // For disassembly. + let NSForm = VLDSTLaneDblFrm.Value; // For disassembly. +} def VLD3d8 : VLD3D<0b0000, "vld3", "8">; def VLD3d16 : VLD3D<0b0100, "vld3", "16">; @@ -260,7 +266,10 @@ (outs DPR:$dst1, DPR:$dst2, DPR:$dst3, DPR:$dst4, GPR:$wb), (ins addrmode6:$addr), IIC_VLD4, OpcodeStr, Dt, "\\{$dst1, $dst2, $dst3, $dst4\\}, $addr", - "$addr.addr = $wb", []>; + "$addr.addr = $wb", []> { + let NSF = VLDSTLaneDblFrm; // For disassembly. + let NSForm = VLDSTLaneDblFrm.Value; // For disassembly. +} def VLD4d8 : VLD4D<0b0000, "vld4", "8">; def VLD4d16 : VLD4D<0b0100, "vld4", "16">; @@ -297,12 +306,28 @@ def VLD2LNd32 : VLD2LN<0b1001, "vld2", "32"> { let Inst{6} = 0; } // vld2 to double-spaced even registers. -def VLD2LNq16a: VLD2LN<0b0101, "vld2", "16"> { let Inst{5} = 1; } -def VLD2LNq32a: VLD2LN<0b1001, "vld2", "32"> { let Inst{6} = 1; } +def VLD2LNq16a: VLD2LN<0b0101, "vld2", "16"> { + let Inst{5} = 1; + let NSF = VLDSTLaneDblFrm; // For disassembly. + let NSForm = VLDSTLaneDblFrm.Value; // For disassembly. +} +def VLD2LNq32a: VLD2LN<0b1001, "vld2", "32"> { + let Inst{6} = 1; + let NSF = VLDSTLaneDblFrm; // For disassembly. + let NSForm = VLDSTLaneDblFrm.Value; // For disassembly. +} // vld2 to double-spaced odd registers. -def VLD2LNq16b: VLD2LN<0b0101, "vld2", "16"> { let Inst{5} = 1; } -def VLD2LNq32b: VLD2LN<0b1001, "vld2", "32"> { let Inst{6} = 1; } +def VLD2LNq16b: VLD2LN<0b0101, "vld2", "16"> { + let Inst{5} = 1; + let NSF = VLDSTLaneDblFrm; // For disassembly. + let NSForm = VLDSTLaneDblFrm.Value; // For disassembly. +} +def VLD2LNq32b: VLD2LN<0b1001, "vld2", "32"> { + let Inst{6} = 1; + let NSF = VLDSTLaneDblFrm; // For disassembly. + let NSForm = VLDSTLaneDblFrm.Value; // For disassembly. +} // VLD3LN : Vector Load (single 3-element structure to one lane) class VLD3LN op11_8, string OpcodeStr, string Dt> @@ -318,7 +343,11 @@ def VLD3LNd32 : VLD3LN<0b1010, "vld3", "32"> { let Inst{6-4} = 0b000; } // vld3 to double-spaced even registers. -def VLD3LNq16a: VLD3LN<0b0110, "vld3", "16"> { let Inst{5-4} = 0b10; } +def VLD3LNq16a: VLD3LN<0b0110, "vld3", "16"> { + let Inst{5-4} = 0b10; + let NSF = VLDSTLaneDblFrm; // For disassembly. + let NSForm = VLDSTLaneDblFrm.Value; // For disassembly. +} def VLD3LNq32a: VLD3LN<0b1010, "vld3", "32"> { let Inst{6-4} = 0b100; } // vld3 to double-spaced odd registers. @@ -340,12 +369,28 @@ def VLD4LNd32 : VLD4LN<0b1011, "vld4", "32"> { let Inst{6} = 0; } // vld4 to double-spaced even registers. -def VLD4LNq16a: VLD4LN<0b0111, "vld4", "16"> { let Inst{5} = 1; } -def VLD4LNq32a: VLD4LN<0b1011, "vld4", "32"> { let Inst{6} = 1; } +def VLD4LNq16a: VLD4LN<0b0111, "vld4", "16"> { + let Inst{5} = 1; + let NSF = VLDSTLaneDblFrm; // For disassembly. + let NSForm = VLDSTLaneDblFrm.Value; // For disassembly. +} +def VLD4LNq32a: VLD4LN<0b1011, "vld4", "32"> { + let Inst{6} = 1; + let NSF = VLDSTLaneDblFrm; // For disassembly. + let NSForm = VLDSTLaneDblFrm.Value; // For disassembly. +} // vld4 to double-spaced odd registers. -def VLD4LNq16b: VLD4LN<0b0111, "vld4", "16"> { let Inst{5} = 1; } -def VLD4LNq32b: VLD4LN<0b1011, "vld4", "32"> { let Inst{6} = 1; } +def VLD4LNq16b: VLD4LN<0b0111, "vld4", "16"> { + let Inst{5} = 1; + let NSF = VLDSTLaneDblFrm; // For disassembly. + let NSForm = VLDSTLaneDblFrm.Value; // For disassembly. +} +def VLD4LNq32b: VLD4LN<0b1011, "vld4", "32"> { + let Inst{6} = 1; + let NSF = VLDSTLaneDblFrm; // For disassembly. + let NSForm = VLDSTLaneDblFrm.Value; // For disassembly. +} // VLD1DUP : Vector Load (single element to all lanes) // VLD2DUP : Vector Load (single 2-element structure to all lanes) @@ -433,7 +478,10 @@ class VST2Ddbl op7_4, string OpcodeStr, string Dt> : NLdSt<0, 0b00, 0b1001, op7_4, (outs), (ins addrmode6:$addr, DPR:$src1, DPR:$src2), IIC_VST, - OpcodeStr, Dt, "\\{$src1, $src2\\}, $addr", "", []>; + OpcodeStr, Dt, "\\{$src1, $src2\\}, $addr", "", []> { + let NSF = VLDSTLaneDblFrm; // For disassembly. + let NSForm = VLDSTLaneDblFrm.Value; // For disassembly. +} def VST2d8D : VST2Ddbl<0b0000, "vst2", "8">; def VST2d16D : VST2Ddbl<0b0100, "vst2", "16">; @@ -448,7 +496,10 @@ : NLdSt<0,0b00,0b0101,op7_4, (outs GPR:$wb), (ins addrmode6:$addr, DPR:$src1, DPR:$src2, DPR:$src3), IIC_VST, OpcodeStr, Dt, "\\{$src1, $src2, $src3\\}, $addr", - "$addr.addr = $wb", []>; + "$addr.addr = $wb", []> { + let NSF = VLDSTLaneDblFrm; // For disassembly. + let NSForm = VLDSTLaneDblFrm.Value; // For disassembly. +} def VST3d8 : VST3D<0b0000, "vst3", "8">; def VST3d16 : VST3D<0b0100, "vst3", "16">; @@ -478,7 +529,10 @@ : NLdSt<0,0b00,0b0001,op7_4, (outs GPR:$wb), (ins addrmode6:$addr, DPR:$src1, DPR:$src2, DPR:$src3, DPR:$src4), IIC_VST, OpcodeStr, Dt, "\\{$src1, $src2, $src3, $src4\\}, $addr", - "$addr.addr = $wb", []>; + "$addr.addr = $wb", []> { + let NSF = VLDSTLaneDblFrm; // For disassembly. + let NSForm = VLDSTLaneDblFrm.Value; // For disassembly. +} def VST4d8 : VST4D<0b0000, "vst4", "8">; def VST4d16 : VST4D<0b0100, "vst4", "16">; @@ -515,12 +569,28 @@ def VST2LNd32 : VST2LN<0b1001, "vst2", "32"> { let Inst{6} = 0; } // vst2 to double-spaced even registers. -def VST2LNq16a: VST2LN<0b0101, "vst2", "16"> { let Inst{5} = 1; } -def VST2LNq32a: VST2LN<0b1001, "vst2", "32"> { let Inst{6} = 1; } +def VST2LNq16a: VST2LN<0b0101, "vst2", "16"> { + let Inst{5} = 1; + let NSF = VLDSTLaneDblFrm; // For disassembly. + let NSForm = VLDSTLaneDblFrm.Value; // For disassembly. +} +def VST2LNq32a: VST2LN<0b1001, "vst2", "32"> { + let Inst{6} = 1; + let NSF = VLDSTLaneDblFrm; // For disassembly. + let NSForm = VLDSTLaneDblFrm.Value; // For disassembly. +} // vst2 to double-spaced odd registers. -def VST2LNq16b: VST2LN<0b0101, "vst2", "16"> { let Inst{5} = 1; } -def VST2LNq32b: VST2LN<0b1001, "vst2", "32"> { let Inst{6} = 1; } +def VST2LNq16b: VST2LN<0b0101, "vst2", "16"> { + let Inst{5} = 1; + let NSF = VLDSTLaneDblFrm; // For disassembly. + let NSForm = VLDSTLaneDblFrm.Value; // For disassembly. +} +def VST2LNq32b: VST2LN<0b1001, "vst2", "32"> { + let Inst{6} = 1; + let NSF = VLDSTLaneDblFrm; // For disassembly. + let NSForm = VLDSTLaneDblFrm.Value; // For disassembly. +} // VST3LN : Vector Store (single 3-element structure from one lane) class VST3LN op11_8, string OpcodeStr, string Dt> @@ -535,12 +605,28 @@ def VST3LNd32 : VST3LN<0b1010, "vst3", "32"> { let Inst{6-4} = 0b000; } // vst3 to double-spaced even registers. -def VST3LNq16a: VST3LN<0b0110, "vst3", "16"> { let Inst{5-4} = 0b10; } -def VST3LNq32a: VST3LN<0b1010, "vst3", "32"> { let Inst{6-4} = 0b100; } +def VST3LNq16a: VST3LN<0b0110, "vst3", "16"> { + let Inst{5-4} = 0b10; + let NSF = VLDSTLaneDblFrm; // For disassembly. + let NSForm = VLDSTLaneDblFrm.Value; // For disassembly. +} +def VST3LNq32a: VST3LN<0b1010, "vst3", "32"> { + let Inst{6-4} = 0b100; + let NSF = VLDSTLaneDblFrm; // For disassembly. + let NSForm = VLDSTLaneDblFrm.Value; // For disassembly. +} // vst3 to double-spaced odd registers. -def VST3LNq16b: VST3LN<0b0110, "vst3", "16"> { let Inst{5-4} = 0b10; } -def VST3LNq32b: VST3LN<0b1010, "vst3", "32"> { let Inst{6-4} = 0b100; } +def VST3LNq16b: VST3LN<0b0110, "vst3", "16"> { + let Inst{5-4} = 0b10; + let NSF = VLDSTLaneDblFrm; // For disassembly. + let NSForm = VLDSTLaneDblFrm.Value; // For disassembly. +} +def VST3LNq32b: VST3LN<0b1010, "vst3", "32"> { + let Inst{6-4} = 0b100; + let NSF = VLDSTLaneDblFrm; // For disassembly. + let NSForm = VLDSTLaneDblFrm.Value; // For disassembly. +} // VST4LN : Vector Store (single 4-element structure from one lane) class VST4LN op11_8, string OpcodeStr, string Dt> @@ -556,12 +642,28 @@ def VST4LNd32 : VST4LN<0b1011, "vst4", "32"> { let Inst{6} = 0; } // vst4 to double-spaced even registers. -def VST4LNq16a: VST4LN<0b0111, "vst4", "16"> { let Inst{5} = 1; } -def VST4LNq32a: VST4LN<0b1011, "vst4", "32"> { let Inst{6} = 1; } +def VST4LNq16a: VST4LN<0b0111, "vst4", "16"> { + let Inst{5} = 1; + let NSF = VLDSTLaneDblFrm; // For disassembly. + let NSForm = VLDSTLaneDblFrm.Value; // For disassembly. +} +def VST4LNq32a: VST4LN<0b1011, "vst4", "32"> { + let Inst{6} = 1; + let NSF = VLDSTLaneDblFrm; // For disassembly. + let NSForm = VLDSTLaneDblFrm.Value; // For disassembly. +} // vst4 to double-spaced odd registers. -def VST4LNq16b: VST4LN<0b0111, "vst4", "16"> { let Inst{5} = 1; } -def VST4LNq32b: VST4LN<0b1011, "vst4", "32"> { let Inst{6} = 1; } +def VST4LNq16b: VST4LN<0b0111, "vst4", "16"> { + let Inst{5} = 1; + let NSF = VLDSTLaneDblFrm; // For disassembly. + let NSForm = VLDSTLaneDblFrm.Value; // For disassembly. +} +def VST4LNq32b: VST4LN<0b1011, "vst4", "32"> { + let Inst{6} = 1; + let NSF = VLDSTLaneDblFrm; // For disassembly. + let NSForm = VLDSTLaneDblFrm.Value; // For disassembly. +} } // mayStore = 1, hasExtraSrcRegAllocReq = 1 @@ -668,12 +770,18 @@ : N2V<0b11, 0b11, op19_18, 0b10, op11_7, 0, 0, (outs DPR:$dst1, DPR:$dst2), (ins DPR:$src1, DPR:$src2), IIC_VPERMD, OpcodeStr, Dt, "$dst1, $dst2", - "$src1 = $dst1, $src2 = $dst2", []>; + "$src1 = $dst1, $src2 = $dst2", []> { + let NSF = NVectorShuffleFrm; // For disassembly. + let NSForm = NVectorShuffleFrm.Value; // For disassembly. +} class N2VQShuffle op19_18, bits<5> op11_7, InstrItinClass itin, string OpcodeStr, string Dt> : N2V<0b11, 0b11, op19_18, 0b10, op11_7, 1, 0, (outs QPR:$dst1, QPR:$dst2), (ins QPR:$src1, QPR:$src2), itin, OpcodeStr, Dt, "$dst1, $dst2", - "$src1 = $dst1, $src2 = $dst2", []>; + "$src1 = $dst1, $src2 = $dst2", []> { + let NSF = NVectorShuffleFrm; // For disassembly. + let NSForm = NVectorShuffleFrm.Value; // For disassembly. +} // Basic 3-register operations: single-, double- and quad-register. class N3VS op21_20, bits<4> op11_8, bit op4, @@ -715,6 +823,8 @@ (Ty (ShOp (Ty DPR:$src1), (Ty (NEONvduplane (Ty DPR_VFP2:$src2), imm:$lane)))))]>{ let isCommutable = 0; + let NSF = NVdVnVmImmMulScalarFrm; // For disassembly. + let NSForm = NVdVnVmImmMulScalarFrm.Value; // For disassembly. } class N3VDSL16 op21_20, bits<4> op11_8, string OpcodeStr, string Dt, ValueType Ty, SDNode ShOp> @@ -725,6 +835,8 @@ (Ty (ShOp (Ty DPR:$src1), (Ty (NEONvduplane (Ty DPR_8:$src2), imm:$lane)))))]> { let isCommutable = 0; + let NSF = NVdVnVmImmMulScalarFrm; // For disassembly. + let NSForm = NVdVnVmImmMulScalarFrm.Value; // For disassembly. } class N3VQ op21_20, bits<4> op11_8, bit op4, @@ -756,6 +868,8 @@ (ResTy (NEONvduplane (OpTy DPR_VFP2:$src2), imm:$lane)))))]> { let isCommutable = 0; + let NSF = NVdVnVmImmMulScalarFrm; // For disassembly. + let NSForm = NVdVnVmImmMulScalarFrm.Value; // For disassembly. } class N3VQSL16 op21_20, bits<4> op11_8, string OpcodeStr, string Dt, ValueType ResTy, ValueType OpTy, SDNode ShOp> @@ -767,6 +881,8 @@ (ResTy (NEONvduplane (OpTy DPR_8:$src2), imm:$lane)))))]> { let isCommutable = 0; + let NSF = NVdVnVmImmMulScalarFrm; // For disassembly. + let NSForm = NVdVnVmImmMulScalarFrm.Value; // For disassembly. } // Basic 3-register intrinsics, both double- and quad-register. @@ -789,6 +905,8 @@ (Ty (NEONvduplane (Ty DPR_VFP2:$src2), imm:$lane)))))]> { let isCommutable = 0; + let NSF = NVdVnVmImmMulScalarFrm; // For disassembly. + let NSForm = NVdVnVmImmMulScalarFrm.Value; // For disassembly. } class N3VDIntSL16 op21_20, bits<4> op11_8, InstrItinClass itin, string OpcodeStr, string Dt, ValueType Ty, Intrinsic IntOp> @@ -800,6 +918,8 @@ (Ty (NEONvduplane (Ty DPR_8:$src2), imm:$lane)))))]> { let isCommutable = 0; + let NSF = NVdVnVmImmMulScalarFrm; // For disassembly. + let NSForm = NVdVnVmImmMulScalarFrm.Value; // For disassembly. } class N3VQInt op21_20, bits<4> op11_8, bit op4, @@ -822,6 +942,8 @@ (ResTy (NEONvduplane (OpTy DPR_VFP2:$src2), imm:$lane)))))]> { let isCommutable = 0; + let NSF = NVdVnVmImmMulScalarFrm; // For disassembly. + let NSForm = NVdVnVmImmMulScalarFrm.Value; // For disassembly. } class N3VQIntSL16 op21_20, bits<4> op11_8, InstrItinClass itin, string OpcodeStr, string Dt, @@ -834,6 +956,8 @@ (ResTy (NEONvduplane (OpTy DPR_8:$src2), imm:$lane)))))]> { let isCommutable = 0; + let NSF = NVdVnVmImmMulScalarFrm; // For disassembly. + let NSForm = NVdVnVmImmMulScalarFrm.Value; // For disassembly. } // Multiply-Add/Sub operations: single-, double- and quad-register. @@ -864,7 +988,10 @@ (Ty (ShOp (Ty DPR:$src1), (Ty (MulOp DPR:$src2, (Ty (NEONvduplane (Ty DPR_VFP2:$src3), - imm:$lane)))))))]>; + imm:$lane)))))))]> { + let NSF = NVdVnVmImmMulScalarFrm; // For disassembly. + let NSForm = NVdVnVmImmMulScalarFrm.Value; // For disassembly. +} class N3VDMulOpSL16 op21_20, bits<4> op11_8, InstrItinClass itin, string OpcodeStr, string Dt, ValueType Ty, SDNode MulOp, SDNode ShOp> @@ -876,7 +1003,10 @@ (Ty (ShOp (Ty DPR:$src1), (Ty (MulOp DPR:$src2, (Ty (NEONvduplane (Ty DPR_8:$src3), - imm:$lane)))))))]>; + imm:$lane)))))))]> { + let NSF = NVdVnVmImmMulScalarFrm; // For disassembly. + let NSForm = NVdVnVmImmMulScalarFrm.Value; // For disassembly. +} class N3VQMulOp op21_20, bits<4> op11_8, bit op4, InstrItinClass itin, string OpcodeStr, string Dt, ValueType Ty, @@ -897,7 +1027,10 @@ (ResTy (ShOp (ResTy QPR:$src1), (ResTy (MulOp QPR:$src2, (ResTy (NEONvduplane (OpTy DPR_VFP2:$src3), - imm:$lane)))))))]>; + imm:$lane)))))))]> { + let NSF = NVdVnVmImmMulScalarFrm; // For disassembly. + let NSForm = NVdVnVmImmMulScalarFrm.Value; // For disassembly. +} class N3VQMulOpSL16 op21_20, bits<4> op11_8, InstrItinClass itin, string OpcodeStr, string Dt, ValueType ResTy, ValueType OpTy, @@ -910,7 +1043,10 @@ (ResTy (ShOp (ResTy QPR:$src1), (ResTy (MulOp QPR:$src2, (ResTy (NEONvduplane (OpTy DPR_8:$src3), - imm:$lane)))))))]>; + imm:$lane)))))))]> { + let NSF = NVdVnVmImmMulScalarFrm; // For disassembly. + let NSForm = NVdVnVmImmMulScalarFrm.Value; // For disassembly. +} // Neon 3-argument intrinsics, both double- and quad-register. // The destination register is also used as the first source operand register. @@ -996,7 +1132,10 @@ [(set (ResTy QPR:$dst), (ResTy (IntOp (OpTy DPR:$src1), (OpTy (NEONvduplane (OpTy DPR_VFP2:$src2), - imm:$lane)))))]>; + imm:$lane)))))]> { + let NSF = NVdVnVmImmMulScalarFrm; // For disassembly. + let NSForm = NVdVnVmImmMulScalarFrm.Value; // For disassembly. +} class N3VLIntSL16 op21_20, bits<4> op11_8, InstrItinClass itin, string OpcodeStr, string Dt, ValueType ResTy, ValueType OpTy, Intrinsic IntOp> @@ -1006,7 +1145,10 @@ [(set (ResTy QPR:$dst), (ResTy (IntOp (OpTy DPR:$src1), (OpTy (NEONvduplane (OpTy DPR_8:$src2), - imm:$lane)))))]>; + imm:$lane)))))]> { + let NSF = NVdVnVmImmMulScalarFrm; // For disassembly. + let NSForm = NVdVnVmImmMulScalarFrm.Value; // For disassembly. +} // Wide 3-register intrinsics. class N3VWInt op21_20, bits<4> op11_8, bit op4, @@ -1055,6 +1197,10 @@ OpcodeStr, Dt, "$dst, $src2", "$src1 = $dst", [(set QPR:$dst, (ResTy (IntOp (ResTy QPR:$src1), (OpTy QPR:$src2))))]>; +// This is a big let * in block to mark these instructions NVectorShiftFrm to +// help the disassembler. +let NSF = NVectorShiftFrm, NSForm = NVectorShiftFrm.Value in { + // Shift by immediate, // both double- and quad-register. class N2VDSh op11_8, bit op7, bit op4, @@ -1072,16 +1218,6 @@ OpcodeStr, Dt, "$dst, $src, $SIMM", "", [(set QPR:$dst, (Ty (OpNode (Ty QPR:$src), (i32 imm:$SIMM))))]>; -// Long shift by immediate. -class N2VLSh op11_8, bit op7, bit op6, bit op4, - string OpcodeStr, string Dt, - ValueType ResTy, ValueType OpTy, SDNode OpNode> - : N2VImm; - // Narrow shift by immediate. class N2VNSh op11_8, bit op7, bit op6, bit op4, InstrItinClass itin, string OpcodeStr, string Dt, @@ -1124,8 +1260,26 @@ OpcodeStr, Dt, "$dst, $src2, $SIMM", "$src1 = $dst", [(set QPR:$dst, (Ty (ShOp QPR:$src1, QPR:$src2, (i32 imm:$SIMM))))]>; +} // End of "let NSF = NVectorShiftFrm, ..." + +// Long shift by immediate. +class N2VLSh op11_8, bit op7, bit op6, bit op4, + string OpcodeStr, string Dt, + ValueType ResTy, ValueType OpTy, SDNode OpNode> + : N2VImm { + // This has a different interpretation of the shift amount encoding than + // NVectorShiftFrm. + let NSF = NVectorShift2Frm; // For disassembly. + let NSForm = NVectorShift2Frm.Value; // For disassembly. +} + // Convert, with fractional bits immediate, // both double- and quad-register. +let NSF = NVdVmImmVCVTFrm, NSForm = NVdVmImmVCVTFrm.Value in { class N2VCvtD op11_8, bit op7, bit op4, string OpcodeStr, string Dt, ValueType ResTy, ValueType OpTy, Intrinsic IntOp> @@ -1140,6 +1294,7 @@ (outs QPR:$dst), (ins QPR:$src, i32imm:$SIMM), IIC_VUNAQ, OpcodeStr, Dt, "$dst, $src, $SIMM", "", [(set QPR:$dst, (ResTy (IntOp (OpTy QPR:$src), (i32 imm:$SIMM))))]>; +} //===----------------------------------------------------------------------===// // Multiclasses @@ -1350,6 +1505,60 @@ v2i64, v2i64, IntOp, Commutable>; } +// Same as N3VInt_QHSD, except they're for Vector Shift (Register) Instructions. +// D:Vd M:Vm N:Vn (notice that M:Vm is the first operand) +// This helps the disassembler. +let NSF = NVdVnVmImmVectorShiftFrm, NSForm = NVdVnVmImmVectorShiftFrm.Value in { +multiclass N3VInt_HS2 op11_8, bit op4, + InstrItinClass itinD16, InstrItinClass itinD32, + InstrItinClass itinQ16, InstrItinClass itinQ32, + string OpcodeStr, string Dt, + Intrinsic IntOp, bit Commutable = 0> { + // 64-bit vector types. + def v4i16 : N3VDInt; + def v2i32 : N3VDInt; + + // 128-bit vector types. + def v8i16 : N3VQInt; + def v4i32 : N3VQInt; +} +multiclass N3VInt_QHS2 op11_8, bit op4, + InstrItinClass itinD16, InstrItinClass itinD32, + InstrItinClass itinQ16, InstrItinClass itinQ32, + string OpcodeStr, string Dt, + Intrinsic IntOp, bit Commutable = 0> + : N3VInt_HS2 { + def v8i8 : N3VDInt; + def v16i8 : N3VQInt; +} +multiclass N3VInt_QHSD2 op11_8, bit op4, + InstrItinClass itinD16, InstrItinClass itinD32, + InstrItinClass itinQ16, InstrItinClass itinQ32, + string OpcodeStr, string Dt, + Intrinsic IntOp, bit Commutable = 0> + : N3VInt_QHS2 { + def v1i64 : N3VDInt; + def v2i64 : N3VQInt; +} +} // Neon Narrowing 3-register vector intrinsics, // source operand element sizes of 16, 32 and 64 bits: @@ -1619,6 +1828,47 @@ // imm6 = xxxxxx } +// Same as N2VSh_QHSD, except the instructions have a differnt interpretation of +// the shift amount. This helps the disassembler. +let NSF = NVectorShift2Frm, NSForm = NVectorShift2Frm.Value in { +multiclass N2VSh_QHSD2 op11_8, bit op4, + InstrItinClass itin, string OpcodeStr, string Dt, + SDNode OpNode> { + // 64-bit vector types. + def v8i8 : N2VDSh { + let Inst{21-19} = 0b001; // imm6 = 001xxx + } + def v4i16 : N2VDSh { + let Inst{21-20} = 0b01; // imm6 = 01xxxx + } + def v2i32 : N2VDSh { + let Inst{21} = 0b1; // imm6 = 1xxxxx + } + def v1i64 : N2VDSh; + // imm6 = xxxxxx + + // 128-bit vector types. + def v16i8 : N2VQSh { + let Inst{21-19} = 0b001; // imm6 = 001xxx + } + def v8i16 : N2VQSh { + let Inst{21-20} = 0b01; // imm6 = 01xxxx + } + def v4i32 : N2VQSh { + let Inst{21} = 0b1; // imm6 = 1xxxxx + } + def v2i64 : N2VQSh; + // imm6 = xxxxxx +} +} // Neon Shift-Accumulate vector operations, // element sizes of 8, 16, 32 and 64 bits: @@ -1699,6 +1949,47 @@ // imm6 = xxxxxx } +// Same as N2VShIns_QHSD, except the instructions have a differnt interpretation +// of the shift amount. This helps the disassembler. +let NSF = NVectorShift2Frm, NSForm = NVectorShift2Frm.Value in { +multiclass N2VShIns_QHSD2 op11_8, bit op4, + string OpcodeStr, SDNode ShOp> { + // 64-bit vector types. + def v8i8 : N2VDShIns { + let Inst{21-19} = 0b001; // imm6 = 001xxx + } + def v4i16 : N2VDShIns { + let Inst{21-20} = 0b01; // imm6 = 01xxxx + } + def v2i32 : N2VDShIns { + let Inst{21} = 0b1; // imm6 = 1xxxxx + } + def v1i64 : N2VDShIns; + // imm6 = xxxxxx + + // 128-bit vector types. + def v16i8 : N2VQShIns { + let Inst{21-19} = 0b001; // imm6 = 001xxx + } + def v8i16 : N2VQShIns { + let Inst{21-20} = 0b01; // imm6 = 01xxxx + } + def v4i32 : N2VQShIns { + let Inst{21} = 0b1; // imm6 = 1xxxxx + } + def v2i64 : N2VQShIns; + // imm6 = xxxxxx +} +} + // Neon Shift Long operations, // element sizes of 8, 16, 32 bits: multiclass N2VLSh_QHS op11_8, bit op7, bit op6, @@ -2329,18 +2620,21 @@ // Vector Shifts. // VSHL : Vector Shift -defm VSHLs : N3VInt_QHSD<0, 0, 0b0100, 0, IIC_VSHLiD, IIC_VSHLiD, IIC_VSHLiQ, - IIC_VSHLiQ, "vshl", "s", int_arm_neon_vshifts, 0>; -defm VSHLu : N3VInt_QHSD<1, 0, 0b0100, 0, IIC_VSHLiD, IIC_VSHLiD, IIC_VSHLiQ, - IIC_VSHLiQ, "vshl", "u", int_arm_neon_vshiftu, 0>; +defm VSHLs : N3VInt_QHSD2<0,0, 0b0100, 0, IIC_VSHLiD, IIC_VSHLiD, IIC_VSHLiQ, + IIC_VSHLiQ, "vshl", "s", int_arm_neon_vshifts, 0>; +defm VSHLu : N3VInt_QHSD2<1,0, 0b0100, 0, IIC_VSHLiD, IIC_VSHLiD, IIC_VSHLiQ, + IIC_VSHLiQ, "vshl", "u", int_arm_neon_vshiftu, 0>; // VSHL : Vector Shift Left (Immediate) -defm VSHLi : N2VSh_QHSD<0, 1, 0b0101, 1, IIC_VSHLiD, "vshl", "i", NEONvshl>; +// (disassembly note: this has a different interpretation of the shift amont) +defm VSHLi : N2VSh_QHSD2<0, 1, 0b0101, 1, IIC_VSHLiD, "vshl", "i", NEONvshl>; // VSHR : Vector Shift Right (Immediate) defm VSHRs : N2VSh_QHSD<0, 1, 0b0000, 1, IIC_VSHLiD, "vshr", "s", NEONvshrs>; defm VSHRu : N2VSh_QHSD<1, 1, 0b0000, 1, IIC_VSHLiD, "vshr", "u", NEONvshru>; // VSHLL : Vector Shift Left Long +// (disassembly note: this has a different interpretation of the shift amont) defm VSHLLs : N2VLSh_QHS<0, 1, 0b1010, 0, 0, 1, "vshll", "s", NEONvshlls>; +// (disassembly note: this has a different interpretation of the shift amont) defm VSHLLu : N2VLSh_QHS<1, 1, 0b1010, 0, 0, 1, "vshll", "u", NEONvshllu>; // VSHLL : Vector Shift Left Long (with maximum shift count) @@ -2350,6 +2644,8 @@ : N2VLSh { let Inst{21-16} = op21_16; + let NSF = NVdVmImmVSHLLFrm; // For disassembly. + let NSForm = NVdVmImmVSHLLFrm.Value; // For disassembly. } def VSHLLi8 : N2VLShMax<1, 1, 0b110010, 0b0011, 0, 0, 0, "vshll", "i8", v8i16, v8i8, NEONvshlli>; @@ -2363,10 +2659,10 @@ NEONvshrn>; // VRSHL : Vector Rounding Shift -defm VRSHLs : N3VInt_QHSD<0,0,0b0101,0, IIC_VSHLi4D, IIC_VSHLi4D, IIC_VSHLi4Q, - IIC_VSHLi4Q, "vrshl", "s", int_arm_neon_vrshifts,0>; -defm VRSHLu : N3VInt_QHSD<1,0,0b0101,0, IIC_VSHLi4D, IIC_VSHLi4D, IIC_VSHLi4Q, - IIC_VSHLi4Q, "vrshl", "u", int_arm_neon_vrshiftu,0>; +defm VRSHLs : N3VInt_QHSD2<0,0,0b0101,0,IIC_VSHLi4D, IIC_VSHLi4D, IIC_VSHLi4Q, + IIC_VSHLi4Q,"vrshl", "s", int_arm_neon_vrshifts,0>; +defm VRSHLu : N3VInt_QHSD2<1,0,0b0101,0,IIC_VSHLi4D, IIC_VSHLi4D, IIC_VSHLi4Q, + IIC_VSHLi4Q,"vrshl", "u", int_arm_neon_vrshiftu,0>; // VRSHR : Vector Rounding Shift Right defm VRSHRs : N2VSh_QHSD<0,1,0b0010,1, IIC_VSHLi4D, "vrshr", "s", NEONvrshrs>; defm VRSHRu : N2VSh_QHSD<1,1,0b0010,1, IIC_VSHLi4D, "vrshr", "u", NEONvrshru>; @@ -2376,15 +2672,18 @@ NEONvrshrn>; // VQSHL : Vector Saturating Shift -defm VQSHLs : N3VInt_QHSD<0,0,0b0100,1, IIC_VSHLi4D, IIC_VSHLi4D, IIC_VSHLi4Q, - IIC_VSHLi4Q, "vqshl", "s", int_arm_neon_vqshifts,0>; -defm VQSHLu : N3VInt_QHSD<1,0,0b0100,1, IIC_VSHLi4D, IIC_VSHLi4D, IIC_VSHLi4Q, - IIC_VSHLi4Q, "vqshl", "u", int_arm_neon_vqshiftu,0>; +defm VQSHLs : N3VInt_QHSD2<0,0,0b0100,1,IIC_VSHLi4D, IIC_VSHLi4D, IIC_VSHLi4Q, + IIC_VSHLi4Q, "vqshl", "s", int_arm_neon_vqshifts,0>; +defm VQSHLu : N3VInt_QHSD2<1,0,0b0100,1,IIC_VSHLi4D, IIC_VSHLi4D, IIC_VSHLi4Q, + IIC_VSHLi4Q, "vqshl", "u", int_arm_neon_vqshiftu,0>; // VQSHL : Vector Saturating Shift Left (Immediate) -defm VQSHLsi : N2VSh_QHSD<0,1,0b0111,1, IIC_VSHLi4D, "vqshl", "s", NEONvqshls>; -defm VQSHLui : N2VSh_QHSD<1,1,0b0111,1, IIC_VSHLi4D, "vqshl", "u", NEONvqshlu>; +// (disassembly note: this has a different interpretation of the shift amont) +defm VQSHLsi : N2VSh_QHSD2<0,1,0b0111,1, IIC_VSHLi4D, "vqshl", "s", NEONvqshls>; +// (disassembly note: this has a different interpretation of the shift amont) +defm VQSHLui : N2VSh_QHSD2<1,1,0b0111,1, IIC_VSHLi4D, "vqshl", "u", NEONvqshlu>; // VQSHLU : Vector Saturating Shift Left (Immediate, Unsigned) -defm VQSHLsu : N2VSh_QHSD<1,1,0b0110,1, IIC_VSHLi4D, "vqshlu","s",NEONvqshlsu>; +// (disassembly note: this has a different interpretation of the shift amont) +defm VQSHLsu : N2VSh_QHSD2<1,1,0b0110,1, IIC_VSHLi4D, "vqshlu","s",NEONvqshlsu>; // VQSHRN : Vector Saturating Shift Right and Narrow defm VQSHRNs : N2VNSh_HSD<0, 1, 0b1001, 0, 0, 1, IIC_VSHLi4D, "vqshrn", "s", @@ -2397,12 +2696,12 @@ NEONvqshrnsu>; // VQRSHL : Vector Saturating Rounding Shift -defm VQRSHLs : N3VInt_QHSD<0,0,0b0101,1, IIC_VSHLi4D, IIC_VSHLi4D, IIC_VSHLi4Q, - IIC_VSHLi4Q, "vqrshl", "s", - int_arm_neon_vqrshifts, 0>; -defm VQRSHLu : N3VInt_QHSD<1,0,0b0101,1, IIC_VSHLi4D, IIC_VSHLi4D, IIC_VSHLi4Q, - IIC_VSHLi4Q, "vqrshl", "u", - int_arm_neon_vqrshiftu, 0>; +defm VQRSHLs : N3VInt_QHSD2<0,0,0b0101,1, IIC_VSHLi4D, IIC_VSHLi4D, IIC_VSHLi4Q, + IIC_VSHLi4Q, "vqrshl", "s", + int_arm_neon_vqrshifts, 0>; +defm VQRSHLu : N3VInt_QHSD2<1,0,0b0101,1, IIC_VSHLi4D, IIC_VSHLi4D, IIC_VSHLi4Q, + IIC_VSHLi4Q, "vqrshl", "u", + int_arm_neon_vqrshiftu, 0>; // VQRSHRN : Vector Saturating Rounding Shift Right and Narrow defm VQRSHRNs : N2VNSh_HSD<0, 1, 0b1001, 0, 1, 1, IIC_VSHLi4D, "vqrshrn", "s", @@ -2422,7 +2721,8 @@ defm VRSRAu : N2VShAdd_QHSD<1, 1, 0b0011, 1, "vrsra", "u", NEONvrshru>; // VSLI : Vector Shift Left and Insert -defm VSLI : N2VShIns_QHSD<1, 1, 0b0101, 1, "vsli", NEONvsli>; +// (disassembly note: this has a different interpretation of the shift amont) +defm VSLI : N2VShIns_QHSD2<1, 1, 0b0101, 1, "vsli", NEONvsli>; // VSRI : Vector Shift Right and Insert defm VSRI : N2VShIns_QHSD<1, 1, 0b0100, 1, "vsri", NEONvsri>; @@ -2518,10 +2818,13 @@ // VMOV : Vector Move (Register) +// Mark these instructions as 2-register instructions to help the disassembler. +let NSF = NVdVmImmFrm, NSForm = NVdVmImmFrm.Value in { def VMOVDneon: N3VX<0, 0, 0b10, 0b0001, 0, 1, (outs DPR:$dst), (ins DPR:$src), IIC_VMOVD, "vmov", "$dst, $src", "", []>; def VMOVQ : N3VX<0, 0, 0b10, 0b0001, 1, 1, (outs QPR:$dst), (ins QPR:$src), IIC_VMOVD, "vmov", "$dst, $src", "", []>; +} // VMOV : Vector Move (Immediate) @@ -2762,6 +3065,7 @@ // VDUP : Vector Duplicate Lane (from scalar to all elements) +let NSF = NVdVmImmVDupLaneFrm, NSForm = NVdVmImmVDupLaneFrm.Value in { class VDUPLND op19_18, bits<2> op17_16, string OpcodeStr, string Dt, ValueType Ty> : N2V<0b11, 0b11, op19_18, op17_16, 0b11000, 0, 0, @@ -2775,6 +3079,7 @@ (outs QPR:$dst), (ins DPR:$src, nohash_imm:$lane), IIC_VMOVD, OpcodeStr, Dt, "$dst, $src[$lane]", "", [(set QPR:$dst, (ResTy (NEONvduplane (OpTy DPR:$src), imm:$lane)))]>; +} // Inst{19-16} is partially specified depending on the element size. @@ -2843,24 +3148,37 @@ // Vector Conversions. +let NSF = NVdVmImmVCVTFrm, NSForm = NVdVmImmVCVTFrm.Value in { +class N2VDX op24_23, bits<2> op21_20, bits<2> op19_18, + bits<2> op17_16, bits<5> op11_7, bit op4, string OpcodeStr, + string Dt, ValueType ResTy, ValueType OpTy, SDNode OpNode> + : N2VD; +class N2VQX op24_23, bits<2> op21_20, bits<2> op19_18, + bits<2> op17_16, bits<5> op11_7, bit op4, string OpcodeStr, + string Dt, ValueType ResTy, ValueType OpTy, SDNode OpNode> + : N2VQ; +} + // VCVT : Vector Convert Between Floating-Point and Integers -def VCVTf2sd : N2VD<0b11, 0b11, 0b10, 0b11, 0b01110, 0, "vcvt", "s32.f32", - v2i32, v2f32, fp_to_sint>; -def VCVTf2ud : N2VD<0b11, 0b11, 0b10, 0b11, 0b01111, 0, "vcvt", "u32.f32", - v2i32, v2f32, fp_to_uint>; -def VCVTs2fd : N2VD<0b11, 0b11, 0b10, 0b11, 0b01100, 0, "vcvt", "f32.s32", - v2f32, v2i32, sint_to_fp>; -def VCVTu2fd : N2VD<0b11, 0b11, 0b10, 0b11, 0b01101, 0, "vcvt", "f32.u32", - v2f32, v2i32, uint_to_fp>; - -def VCVTf2sq : N2VQ<0b11, 0b11, 0b10, 0b11, 0b01110, 0, "vcvt", "s32.f32", - v4i32, v4f32, fp_to_sint>; -def VCVTf2uq : N2VQ<0b11, 0b11, 0b10, 0b11, 0b01111, 0, "vcvt", "u32.f32", - v4i32, v4f32, fp_to_uint>; -def VCVTs2fq : N2VQ<0b11, 0b11, 0b10, 0b11, 0b01100, 0, "vcvt", "f32.s32", - v4f32, v4i32, sint_to_fp>; -def VCVTu2fq : N2VQ<0b11, 0b11, 0b10, 0b11, 0b01101, 0, "vcvt", "f32.u32", - v4f32, v4i32, uint_to_fp>; +def VCVTf2sd : N2VDX<0b11, 0b11, 0b10, 0b11, 0b01110, 0, "vcvt", "s32.f32", + v2i32, v2f32, fp_to_sint>; +def VCVTf2ud : N2VDX<0b11, 0b11, 0b10, 0b11, 0b01111, 0, "vcvt", "u32.f32", + v2i32, v2f32, fp_to_uint>; +def VCVTs2fd : N2VDX<0b11, 0b11, 0b10, 0b11, 0b01100, 0, "vcvt", "f32.s32", + v2f32, v2i32, sint_to_fp>; +def VCVTu2fd : N2VDX<0b11, 0b11, 0b10, 0b11, 0b01101, 0, "vcvt", "f32.u32", + v2f32, v2i32, uint_to_fp>; + +def VCVTf2sq : N2VQX<0b11, 0b11, 0b10, 0b11, 0b01110, 0, "vcvt", "s32.f32", + v4i32, v4f32, fp_to_sint>; +def VCVTf2uq : N2VQX<0b11, 0b11, 0b10, 0b11, 0b01111, 0, "vcvt", "u32.f32", + v4i32, v4f32, fp_to_uint>; +def VCVTs2fq : N2VQX<0b11, 0b11, 0b10, 0b11, 0b01100, 0, "vcvt", "f32.s32", + v4f32, v4i32, sint_to_fp>; +def VCVTu2fq : N2VQX<0b11, 0b11, 0b10, 0b11, 0b01101, 0, "vcvt", "f32.u32", + v4f32, v4i32, uint_to_fp>; // VCVT : Vector Convert Between Floating-Point and Fixed-Point. def VCVTf2xsd : N2VCvtD<0, 1, 0b1111, 0, 1, "vcvt", "s32.f32", @@ -2945,6 +3263,8 @@ // VEXT : Vector Extract +let NSF = NVdVnVmImmVectorExtractFrm, + NSForm = NVdVnVmImmVectorExtractFrm.Value in { class VEXTd : N3V<0,1,0b11,{?,?,?,?},0,0, (outs DPR:$dst), (ins DPR:$lhs, DPR:$rhs, i32imm:$index), IIC_VEXTD, @@ -2958,6 +3278,7 @@ OpcodeStr, Dt, "$dst, $lhs, $rhs, $index", "", [(set QPR:$dst, (Ty (NEONvext (Ty QPR:$lhs), (Ty QPR:$rhs), imm:$index)))]>; +} def VEXTd8 : VEXTd<"vext", "8", v8i8>; def VEXTd16 : VEXTd<"vext", "16", v4i16>; @@ -3001,6 +3322,8 @@ // Vector Table Lookup and Table Extension. +let NSF = VTBLFrm, NSForm = VTBLFrm.Value in { + // VTBL : Vector Table Lookup def VTBL1 : N3V<1,1,0b11,0b1000,0,0, (outs DPR:$dst), @@ -3057,6 +3380,8 @@ DPR:$tbl2, DPR:$tbl3, DPR:$tbl4, DPR:$src)))]>; } // hasExtraSrcRegAllocReq = 1 +} // End of "let NSF = VTBLFrm, ..." + //===----------------------------------------------------------------------===// // NEON instructions for single-precision FP math //===----------------------------------------------------------------------===// Modified: llvm/trunk/lib/Target/ARM/AsmPrinter/ARMAsmPrinter.cpp URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Target/ARM/AsmPrinter/ARMAsmPrinter.cpp?rev=98745&r1=98744&r2=98745&view=diff ============================================================================== --- llvm/trunk/lib/Target/ARM/AsmPrinter/ARMAsmPrinter.cpp (original) +++ llvm/trunk/lib/Target/ARM/AsmPrinter/ARMAsmPrinter.cpp Wed Mar 17 12:52:21 2010 @@ -120,7 +120,7 @@ void printT2AddrModeImm8Operand(const MachineInstr *MI, int OpNum); void printT2AddrModeImm8s4Operand(const MachineInstr *MI, int OpNum); void printT2AddrModeImm8OffsetOperand(const MachineInstr *MI, int OpNum); - void printT2AddrModeImm8s4OffsetOperand(const MachineInstr *MI, int OpNum) {} + void printT2AddrModeImm8s4OffsetOperand(const MachineInstr *MI, int OpNum); void printT2AddrModeSoRegOperand(const MachineInstr *MI, int OpNum); void printCPSOptionOperand(const MachineInstr *MI, int OpNum) {} @@ -431,16 +431,16 @@ O << "[" << getRegisterName(MO1.getReg()); if (!MO2.getReg()) { - if (ARM_AM::getAM2Offset(MO3.getImm())) // Don't print +0. + if (ARM_AM::getAM2Offset(MO3.getImm())) // Don't print +0. O << ", #" - << (char)ARM_AM::getAM2Op(MO3.getImm()) + << ARM_AM::getAddrOpcStr(ARM_AM::getAM2Op(MO3.getImm())) << ARM_AM::getAM2Offset(MO3.getImm()); O << "]"; return; } O << ", " - << (char)ARM_AM::getAM2Op(MO3.getImm()) + << ARM_AM::getAddrOpcStr(ARM_AM::getAM2Op(MO3.getImm())) << getRegisterName(MO2.getReg()); if (unsigned ShImm = ARM_AM::getAM2Offset(MO3.getImm())) @@ -458,12 +458,12 @@ unsigned ImmOffs = ARM_AM::getAM2Offset(MO2.getImm()); assert(ImmOffs && "Malformed indexed load / store!"); O << "#" - << (char)ARM_AM::getAM2Op(MO2.getImm()) + << ARM_AM::getAddrOpcStr(ARM_AM::getAM2Op(MO2.getImm())) << ImmOffs; return; } - O << (char)ARM_AM::getAM2Op(MO2.getImm()) + O << ARM_AM::getAddrOpcStr(ARM_AM::getAM2Op(MO2.getImm())) << getRegisterName(MO1.getReg()); if (unsigned ShImm = ARM_AM::getAM2Offset(MO2.getImm())) @@ -490,7 +490,7 @@ if (unsigned ImmOffs = ARM_AM::getAM3Offset(MO3.getImm())) O << ", #" - << (char)ARM_AM::getAM3Op(MO3.getImm()) + << ARM_AM::getAddrOpcStr(ARM_AM::getAM3Op(MO3.getImm())) << ImmOffs; O << "]"; } @@ -508,7 +508,7 @@ unsigned ImmOffs = ARM_AM::getAM3Offset(MO2.getImm()); assert(ImmOffs && "Malformed indexed load / store!"); O << "#" - << (char)ARM_AM::getAM3Op(MO2.getImm()) + << ARM_AM::getAddrOpcStr(ARM_AM::getAM3Op(MO2.getImm())) << ImmOffs; } @@ -553,7 +553,7 @@ if (unsigned ImmOffs = ARM_AM::getAM5Offset(MO2.getImm())) { O << ", #" - << (char)ARM_AM::getAM5Op(MO2.getImm()) + << ARM_AM::getAddrOpcStr(ARM_AM::getAM5Op(MO2.getImm())) << ImmOffs*4; } O << "]"; @@ -589,7 +589,7 @@ const MachineOperand &MO1 = MI->getOperand(Op); assert(TargetRegisterInfo::isPhysicalRegister(MO1.getReg())); - O << "[pc, +" << getRegisterName(MO1.getReg()) << "]"; + O << "[pc, " << getRegisterName(MO1.getReg()) << "]"; } void @@ -612,10 +612,11 @@ ARMAsmPrinter::printThumbITMask(const MachineInstr *MI, int Op) { // (3 - the number of trailing zeros) is the number of then / else. unsigned Mask = MI->getOperand(Op).getImm(); + unsigned CondBit0 = Mask >> 4 & 1; unsigned NumTZ = CountTrailingZeros_32(Mask); assert(NumTZ <= 3 && "Invalid IT mask!"); for (unsigned Pos = 3, e = NumTZ; Pos > e; --Pos) { - bool T = (Mask & (1 << Pos)) == 0; + bool T = ((Mask >> Pos) & 1) == CondBit0; if (T) O << 't'; else @@ -647,7 +648,7 @@ if (MO3.getReg()) O << ", " << getRegisterName(MO3.getReg()); else if (unsigned ImmOffs = MO2.getImm()) - O << ", #+" << ImmOffs * Scale; + O << ", #" << ImmOffs * Scale; O << "]"; } @@ -669,7 +670,7 @@ const MachineOperand &MO2 = MI->getOperand(Op+1); O << "[" << getRegisterName(MO1.getReg()); if (unsigned ImmOffs = MO2.getImm()) - O << ", #+" << ImmOffs*4; + O << ", #" << ImmOffs*4; O << "]"; } @@ -705,7 +706,7 @@ unsigned OffImm = MO2.getImm(); if (OffImm) // Don't print +0. - O << ", #+" << OffImm; + O << ", #" << OffImm; O << "]"; } @@ -721,7 +722,7 @@ if (OffImm < 0) O << ", #-" << -OffImm; else if (OffImm > 0) - O << ", #+" << OffImm; + O << ", #" << OffImm; O << "]"; } @@ -737,7 +738,7 @@ if (OffImm < 0) O << ", #-" << -OffImm * 4; else if (OffImm > 0) - O << ", #+" << OffImm * 4; + O << ", #" << OffImm * 4; O << "]"; } @@ -749,7 +750,18 @@ if (OffImm < 0) O << "#-" << -OffImm; else if (OffImm > 0) - O << "#+" << OffImm; + O << "#" << OffImm; +} + +void ARMAsmPrinter::printT2AddrModeImm8s4OffsetOperand(const MachineInstr *MI, + int OpNum) { + const MachineOperand &MO1 = MI->getOperand(OpNum); + int32_t OffImm = (int32_t)MO1.getImm() / 4; + // Don't print +0. + if (OffImm < 0) + O << "#-" << -OffImm * 4; + else if (OffImm > 0) + O << "#" << OffImm * 4; } void ARMAsmPrinter::printT2AddrModeSoRegOperand(const MachineInstr *MI, Modified: llvm/trunk/lib/Target/ARM/AsmPrinter/ARMInstPrinter.cpp URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Target/ARM/AsmPrinter/ARMInstPrinter.cpp?rev=98745&r1=98744&r2=98745&view=diff ============================================================================== --- llvm/trunk/lib/Target/ARM/AsmPrinter/ARMInstPrinter.cpp (original) +++ llvm/trunk/lib/Target/ARM/AsmPrinter/ARMInstPrinter.cpp Wed Mar 17 12:52:21 2010 @@ -28,7 +28,159 @@ #undef MachineInstr #undef ARMAsmPrinter -void ARMInstPrinter::printInst(const MCInst *MI) { printInstruction(MI); } +static unsigned NextReg(unsigned Reg) { + switch (Reg) { + case ARM::D0: + return ARM::D1; + case ARM::D1: + return ARM::D2; + case ARM::D2: + return ARM::D3; + case ARM::D3: + return ARM::D4; + case ARM::D4: + return ARM::D5; + case ARM::D5: + return ARM::D6; + case ARM::D6: + return ARM::D7; + case ARM::D7: + return ARM::D8; + case ARM::D8: + return ARM::D9; + case ARM::D9: + return ARM::D10; + case ARM::D10: + return ARM::D11; + case ARM::D11: + return ARM::D12; + case ARM::D12: + return ARM::D13; + case ARM::D13: + return ARM::D14; + case ARM::D14: + return ARM::D15; + case ARM::D15: + return ARM::D16; + case ARM::D16: + return ARM::D17; + case ARM::D17: + return ARM::D18; + case ARM::D18: + return ARM::D19; + case ARM::D19: + return ARM::D20; + case ARM::D20: + return ARM::D21; + case ARM::D21: + return ARM::D22; + case ARM::D22: + return ARM::D23; + case ARM::D23: + return ARM::D24; + case ARM::D24: + return ARM::D25; + case ARM::D25: + return ARM::D26; + case ARM::D26: + return ARM::D27; + case ARM::D27: + return ARM::D28; + case ARM::D28: + return ARM::D29; + case ARM::D29: + return ARM::D30; + case ARM::D30: + return ARM::D31; + + default: + assert(0 && "Unexpected register enum"); + } +} + +void ARMInstPrinter::printInst(const MCInst *MI) { + // Check for MOVs and print canonical forms, instead. + if (MI->getOpcode() == ARM::MOVs) { + const MCOperand &Dst = MI->getOperand(0); + const MCOperand &MO1 = MI->getOperand(1); + const MCOperand &MO2 = MI->getOperand(2); + const MCOperand &MO3 = MI->getOperand(3); + + O << '\t' << ARM_AM::getShiftOpcStr(ARM_AM::getSORegShOp(MO3.getImm())); + printSBitModifierOperand(MI, 6); + printPredicateOperand(MI, 4); + + O << '\t' << getRegisterName(Dst.getReg()) + << ", " << getRegisterName(MO1.getReg()); + + if (ARM_AM::getSORegShOp(MO3.getImm()) == ARM_AM::rrx) + return; + + O << ", "; + + if (MO2.getReg()) { + O << getRegisterName(MO2.getReg()); + assert(ARM_AM::getSORegOffset(MO3.getImm()) == 0); + } else { + O << "#" << ARM_AM::getSORegOffset(MO3.getImm()); + } + return; + } + + // A8.6.123 PUSH + if ((MI->getOpcode() == ARM::STM_UPD || MI->getOpcode() == ARM::t2STM_UPD) && + MI->getOperand(0).getReg() == ARM::SP) { + const MCOperand &MO1 = MI->getOperand(2); + if (ARM_AM::getAM4SubMode(MO1.getImm()) == ARM_AM::db) { + O << '\t' << "push"; + printPredicateOperand(MI, 3); + O << '\t'; + printRegisterList(MI, 5); + return; + } + } + + // A8.6.122 POP + if ((MI->getOpcode() == ARM::LDM_UPD || MI->getOpcode() == ARM::t2LDM_UPD) && + MI->getOperand(0).getReg() == ARM::SP) { + const MCOperand &MO1 = MI->getOperand(2); + if (ARM_AM::getAM4SubMode(MO1.getImm()) == ARM_AM::ia) { + O << '\t' << "pop"; + printPredicateOperand(MI, 3); + O << '\t'; + printRegisterList(MI, 5); + return; + } + } + + // A8.6.355 VPUSH + if ((MI->getOpcode() == ARM::VSTMS_UPD || MI->getOpcode() ==ARM::VSTMD_UPD) && + MI->getOperand(0).getReg() == ARM::SP) { + const MCOperand &MO1 = MI->getOperand(2); + if (ARM_AM::getAM5SubMode(MO1.getImm()) == ARM_AM::db) { + O << '\t' << "vpush"; + printPredicateOperand(MI, 3); + O << '\t'; + printRegisterList(MI, 5); + return; + } + } + + // A8.6.354 VPOP + if ((MI->getOpcode() == ARM::VLDMS_UPD || MI->getOpcode() ==ARM::VLDMD_UPD) && + MI->getOperand(0).getReg() == ARM::SP) { + const MCOperand &MO1 = MI->getOperand(2); + if (ARM_AM::getAM5SubMode(MO1.getImm()) == ARM_AM::ia) { + O << '\t' << "vpop"; + printPredicateOperand(MI, 3); + O << '\t'; + printRegisterList(MI, 5); + return; + } + } + + printInstruction(MI); + } void ARMInstPrinter::printOperand(const MCInst *MI, unsigned OpNo, const char *Modifier) { @@ -36,6 +188,9 @@ if (Op.isReg()) { unsigned Reg = Op.getReg(); if (Modifier && strcmp(Modifier, "dregpair") == 0) { + O << '{' << getRegisterName(Reg) << ", " + << getRegisterName(NextReg(Reg)) << '}'; +#if 0 // FIXME: Breaks e.g. ARM/vmul.ll. assert(0); /* @@ -44,6 +199,7 @@ O << '{' << getRegisterName(DRegLo) << ',' << getRegisterName(DRegHi) << '}';*/ +#endif } else if (Modifier && strcmp(Modifier, "lane") == 0) { assert(0); /* @@ -56,7 +212,9 @@ O << getRegisterName(Reg); } } else if (Op.isImm()) { - assert((Modifier == 0 || Modifier[0] == 0) && "No modifiers supported"); + bool isCallOp = Modifier && !strcmp(Modifier, "call"); + assert(isCallOp || + ((Modifier == 0 || Modifier[0] == 0) && "No modifiers supported")); O << '#' << Op.getImm(); } else { assert((Modifier == 0 || Modifier[0] == 0) && "No modifiers supported"); @@ -142,17 +300,17 @@ O << "[" << getRegisterName(MO1.getReg()); if (!MO2.getReg()) { - if (ARM_AM::getAM2Offset(MO3.getImm())) // Don't print +0. + if (ARM_AM::getAM2Offset(MO3.getImm())) // Don't print +0. O << ", #" - << (char)ARM_AM::getAM2Op(MO3.getImm()) - << ARM_AM::getAM2Offset(MO3.getImm()); + << ARM_AM::getAddrOpcStr(ARM_AM::getAM2Op(MO3.getImm())) + << ARM_AM::getAM2Offset(MO3.getImm()); O << "]"; return; } O << ", " - << (char)ARM_AM::getAM2Op(MO3.getImm()) - << getRegisterName(MO2.getReg()); + << ARM_AM::getAddrOpcStr(ARM_AM::getAM2Op(MO3.getImm())) + << getRegisterName(MO2.getReg()); if (unsigned ShImm = ARM_AM::getAM2Offset(MO3.getImm())) O << ", " @@ -169,11 +327,14 @@ if (!MO1.getReg()) { unsigned ImmOffs = ARM_AM::getAM2Offset(MO2.getImm()); assert(ImmOffs && "Malformed indexed load / store!"); - O << '#' << (char)ARM_AM::getAM2Op(MO2.getImm()) << ImmOffs; + O << '#' + << ARM_AM::getAddrOpcStr(ARM_AM::getAM2Op(MO2.getImm())) + << ImmOffs; return; } - O << (char)ARM_AM::getAM2Op(MO2.getImm()) << getRegisterName(MO1.getReg()); + O << ARM_AM::getAddrOpcStr(ARM_AM::getAM2Op(MO2.getImm())) + << getRegisterName(MO1.getReg()); if (unsigned ShImm = ARM_AM::getAM2Offset(MO2.getImm())) O << ", " @@ -196,8 +357,8 @@ if (unsigned ImmOffs = ARM_AM::getAM3Offset(MO3.getImm())) O << ", #" - << (char)ARM_AM::getAM3Op(MO3.getImm()) - << ImmOffs; + << ARM_AM::getAddrOpcStr(ARM_AM::getAM3Op(MO3.getImm())) + << ImmOffs; O << ']'; } @@ -214,9 +375,9 @@ unsigned ImmOffs = ARM_AM::getAM3Offset(MO2.getImm()); assert(ImmOffs && "Malformed indexed load / store!"); - O << "#" - << (char)ARM_AM::getAM3Op(MO2.getImm()) - << ImmOffs; + O << '#' + << ARM_AM::getAddrOpcStr(ARM_AM::getAM3Op(MO2.getImm())) + << ImmOffs; } @@ -259,7 +420,7 @@ if (unsigned ImmOffs = ARM_AM::getAM5Offset(MO2.getImm())) { O << ", #" - << (char)ARM_AM::getAM5Op(MO2.getImm()) + << ARM_AM::getAddrOpcStr(ARM_AM::getAM5Op(MO2.getImm())) << ImmOffs*4; } O << "]"; @@ -298,14 +459,56 @@ void ARMInstPrinter::printRegisterList(const MCInst *MI, unsigned OpNum) { O << "{"; - // Always skip the first operand, it's the optional (and implicit writeback). - for (unsigned i = OpNum+1, e = MI->getNumOperands(); i != e; ++i) { - if (i != OpNum+1) O << ", "; + for (unsigned i = OpNum, e = MI->getNumOperands(); i != e; ++i) { + if (i != OpNum) O << ", "; O << getRegisterName(MI->getOperand(i).getReg()); } O << "}"; } +void ARMInstPrinter::printCPSOptionOperand(const MCInst *MI, unsigned OpNum) { + const MCOperand &Op = MI->getOperand(OpNum); + unsigned option = Op.getImm(); + unsigned mode = option & 31; + bool changemode = option >> 5 & 1; + unsigned AIF = option >> 6 & 7; + unsigned imod = option >> 9 & 3; + if (imod == 2) + O << "ie"; + else if (imod == 3) + O << "id"; + O << '\t'; + if (imod > 1) { + if (AIF & 4) O << 'a'; + if (AIF & 2) O << 'i'; + if (AIF & 1) O << 'f'; + if (AIF > 0 && changemode) O << ", "; + } + if (changemode) + O << '#' << mode; +} + +void ARMInstPrinter::printMSRMaskOperand(const MCInst *MI, unsigned OpNum) { + const MCOperand &Op = MI->getOperand(OpNum); + unsigned Mask = Op.getImm(); + if (Mask) { + O << '_'; + if (Mask & 8) O << 'f'; + if (Mask & 4) O << 's'; + if (Mask & 2) O << 'x'; + if (Mask & 1) O << 'c'; + } +} + +void ARMInstPrinter::printNegZeroOperand(const MCInst *MI, unsigned OpNum){ + const MCOperand &Op = MI->getOperand(OpNum); + O << '#'; + if (Op.getImm() < 0) + O << '-' << (-Op.getImm() - 1); + else + O << Op.getImm(); +} + void ARMInstPrinter::printPredicateOperand(const MCInst *MI, unsigned OpNum) { ARMCC::CondCodes CC = (ARMCC::CondCodes)MI->getOperand(OpNum).getImm(); if (CC != ARMCC::AL) @@ -347,3 +550,191 @@ void ARMInstPrinter::printThumbS4ImmOperand(const MCInst *MI, unsigned OpNum) { O << "#" << MI->getOperand(OpNum).getImm() * 4; } + +void ARMInstPrinter::printThumbITMask(const MCInst *MI, unsigned OpNum) { + // (3 - the number of trailing zeros) is the number of then / else. + unsigned Mask = MI->getOperand(OpNum).getImm(); + unsigned CondBit0 = Mask >> 4 & 1; + unsigned NumTZ = CountTrailingZeros_32(Mask); + assert(NumTZ <= 3 && "Invalid IT mask!"); + for (unsigned Pos = 3, e = NumTZ; Pos > e; --Pos) { + bool T = ((Mask >> Pos) & 1) == CondBit0; + if (T) + O << 't'; + else + O << 'e'; + } +} + +void ARMInstPrinter::printThumbAddrModeRROperand(const MCInst *MI, unsigned Op) +{ + const MCOperand &MO1 = MI->getOperand(Op); + const MCOperand &MO2 = MI->getOperand(Op+1); + O << "[" << getRegisterName(MO1.getReg()); + O << ", " << getRegisterName(MO2.getReg()) << "]"; +} + +void ARMInstPrinter::printThumbAddrModeRI5Operand(const MCInst *MI, unsigned Op, + unsigned Scale) { + const MCOperand &MO1 = MI->getOperand(Op); + const MCOperand &MO2 = MI->getOperand(Op+1); + const MCOperand &MO3 = MI->getOperand(Op+2); + + if (!MO1.isReg()) { // FIXME: This is for CP entries, but isn't right. + printOperand(MI, Op); + return; + } + + O << "[" << getRegisterName(MO1.getReg()); + if (MO3.getReg()) + O << ", " << getRegisterName(MO3.getReg()); + else if (unsigned ImmOffs = MO2.getImm()) + O << ", #" << ImmOffs * Scale; + O << "]"; +} + +void ARMInstPrinter::printThumbAddrModeS1Operand(const MCInst *MI, unsigned Op) +{ + printThumbAddrModeRI5Operand(MI, Op, 1); +} + +void ARMInstPrinter::printThumbAddrModeS2Operand(const MCInst *MI, unsigned Op) +{ + printThumbAddrModeRI5Operand(MI, Op, 2); +} + +void ARMInstPrinter::printThumbAddrModeS4Operand(const MCInst *MI, unsigned Op) +{ + printThumbAddrModeRI5Operand(MI, Op, 4); +} + +void ARMInstPrinter::printThumbAddrModeSPOperand(const MCInst *MI,unsigned Op) { + const MCOperand &MO1 = MI->getOperand(Op); + const MCOperand &MO2 = MI->getOperand(Op+1); + O << "[" << getRegisterName(MO1.getReg()); + if (unsigned ImmOffs = MO2.getImm()) + O << ", #" << ImmOffs*4; + O << "]"; +} + +void ARMInstPrinter::printTBAddrMode(const MCInst *MI, unsigned OpNum) { + O << "[pc, " << getRegisterName(MI->getOperand(OpNum).getReg()); + if (MI->getOpcode() == ARM::t2TBH) + O << ", lsl #1"; + O << ']'; +} + +// Constant shifts t2_so_reg is a 2-operand unit corresponding to the Thumb2 +// register with shift forms. +// REG 0 0 - e.g. R5 +// REG IMM, SH_OPC - e.g. R5, LSL #3 +void ARMInstPrinter::printT2SOOperand(const MCInst *MI, unsigned OpNum) { + const MCOperand &MO1 = MI->getOperand(OpNum); + const MCOperand &MO2 = MI->getOperand(OpNum+1); + + unsigned Reg = MO1.getReg(); + O << getRegisterName(Reg); + + // Print the shift opc. + O << ", " + << ARM_AM::getShiftOpcStr(ARM_AM::getSORegShOp(MO2.getImm())) + << " "; + + assert(MO2.isImm() && "Not a valid t2_so_reg value!"); + O << "#" << ARM_AM::getSORegOffset(MO2.getImm()); +} + +void ARMInstPrinter::printT2AddrModeImm12Operand(const MCInst *MI, + unsigned OpNum) { + const MCOperand &MO1 = MI->getOperand(OpNum); + const MCOperand &MO2 = MI->getOperand(OpNum+1); + + O << "[" << getRegisterName(MO1.getReg()); + + unsigned OffImm = MO2.getImm(); + if (OffImm) // Don't print +0. + O << ", #" << OffImm; + O << "]"; +} + +void ARMInstPrinter::printT2AddrModeImm8Operand(const MCInst *MI, + unsigned OpNum) { + const MCOperand &MO1 = MI->getOperand(OpNum); + const MCOperand &MO2 = MI->getOperand(OpNum+1); + + O << "[" << getRegisterName(MO1.getReg()); + + int32_t OffImm = (int32_t)MO2.getImm(); + // Don't print +0. + if (OffImm < 0) + O << ", #-" << -OffImm; + else if (OffImm > 0) + O << ", #" << OffImm; + O << "]"; +} + +void ARMInstPrinter::printT2AddrModeImm8s4Operand(const MCInst *MI, + unsigned OpNum) { + const MCOperand &MO1 = MI->getOperand(OpNum); + const MCOperand &MO2 = MI->getOperand(OpNum+1); + + O << "[" << getRegisterName(MO1.getReg()); + + int32_t OffImm = (int32_t)MO2.getImm() / 4; + // Don't print +0. + if (OffImm < 0) + O << ", #-" << -OffImm * 4; + else if (OffImm > 0) + O << ", #" << OffImm * 4; + O << "]"; +} + +void ARMInstPrinter::printT2AddrModeImm8OffsetOperand(const MCInst *MI, + unsigned OpNum) { + const MCOperand &MO1 = MI->getOperand(OpNum); + int32_t OffImm = (int32_t)MO1.getImm(); + // Don't print +0. + if (OffImm < 0) + O << "#-" << -OffImm; + else if (OffImm > 0) + O << "#" << OffImm; +} + +void ARMInstPrinter::printT2AddrModeImm8s4OffsetOperand(const MCInst *MI, + unsigned OpNum) { + const MCOperand &MO1 = MI->getOperand(OpNum); + int32_t OffImm = (int32_t)MO1.getImm() / 4; + // Don't print +0. + if (OffImm < 0) + O << "#-" << -OffImm * 4; + else if (OffImm > 0) + O << "#" << OffImm * 4; +} + +void ARMInstPrinter::printT2AddrModeSoRegOperand(const MCInst *MI, + unsigned OpNum) { + const MCOperand &MO1 = MI->getOperand(OpNum); + const MCOperand &MO2 = MI->getOperand(OpNum+1); + const MCOperand &MO3 = MI->getOperand(OpNum+2); + + O << "[" << getRegisterName(MO1.getReg()); + + assert(MO2.getReg() && "Invalid so_reg load / store address!"); + O << ", " << getRegisterName(MO2.getReg()); + + unsigned ShAmt = MO3.getImm(); + if (ShAmt) { + assert(ShAmt <= 3 && "Not a valid Thumb2 addressing mode!"); + O << ", lsl #" << ShAmt; + } + O << "]"; +} + +void ARMInstPrinter::printVFPf32ImmOperand(const MCInst *MI, unsigned OpNum) { + O << '#' << MI->getOperand(OpNum).getImm(); +} + +void ARMInstPrinter::printVFPf64ImmOperand(const MCInst *MI, unsigned OpNum) { + O << '#' << MI->getOperand(OpNum).getImm(); +} + Modified: llvm/trunk/lib/Target/ARM/AsmPrinter/ARMInstPrinter.h URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Target/ARM/AsmPrinter/ARMInstPrinter.h?rev=98745&r1=98744&r2=98745&view=diff ============================================================================== --- llvm/trunk/lib/Target/ARM/AsmPrinter/ARMInstPrinter.h (original) +++ llvm/trunk/lib/Target/ARM/AsmPrinter/ARMInstPrinter.h Wed Mar 17 12:52:21 2010 @@ -54,26 +54,26 @@ void printBitfieldInvMaskImmOperand(const MCInst *MI, unsigned OpNum); void printThumbS4ImmOperand(const MCInst *MI, unsigned OpNum); - void printThumbITMask(const MCInst *MI, unsigned OpNum) {} - void printThumbAddrModeRROperand(const MCInst *MI, unsigned OpNum) {} + void printThumbITMask(const MCInst *MI, unsigned OpNum); + void printThumbAddrModeRROperand(const MCInst *MI, unsigned OpNum); void printThumbAddrModeRI5Operand(const MCInst *MI, unsigned OpNum, - unsigned Scale) {} - void printThumbAddrModeS1Operand(const MCInst *MI, unsigned OpNum) {} - void printThumbAddrModeS2Operand(const MCInst *MI, unsigned OpNum) {} - void printThumbAddrModeS4Operand(const MCInst *MI, unsigned OpNum) {} - void printThumbAddrModeSPOperand(const MCInst *MI, unsigned OpNum) {} + unsigned Scale); + void printThumbAddrModeS1Operand(const MCInst *MI, unsigned OpNum); + void printThumbAddrModeS2Operand(const MCInst *MI, unsigned OpNum); + void printThumbAddrModeS4Operand(const MCInst *MI, unsigned OpNum); + void printThumbAddrModeSPOperand(const MCInst *MI, unsigned OpNum); - void printT2SOOperand(const MCInst *MI, unsigned OpNum) {} - void printT2AddrModeImm12Operand(const MCInst *MI, unsigned OpNum) {} - void printT2AddrModeImm8Operand(const MCInst *MI, unsigned OpNum) {} - void printT2AddrModeImm8s4Operand(const MCInst *MI, unsigned OpNum) {} - void printT2AddrModeImm8OffsetOperand(const MCInst *MI, unsigned OpNum) {} - void printT2AddrModeImm8s4OffsetOperand(const MCInst *MI, unsigned OpNum) {} - void printT2AddrModeSoRegOperand(const MCInst *MI, unsigned OpNum) {} + void printT2SOOperand(const MCInst *MI, unsigned OpNum); + void printT2AddrModeImm12Operand(const MCInst *MI, unsigned OpNum); + void printT2AddrModeImm8Operand(const MCInst *MI, unsigned OpNum); + void printT2AddrModeImm8s4Operand(const MCInst *MI, unsigned OpNum); + void printT2AddrModeImm8OffsetOperand(const MCInst *MI, unsigned OpNum); + void printT2AddrModeImm8s4OffsetOperand(const MCInst *MI, unsigned OpNum); + void printT2AddrModeSoRegOperand(const MCInst *MI, unsigned OpNum); - void printCPSOptionOperand(const MCInst *MI, unsigned OpNum) {} - void printMSRMaskOperand(const MCInst *MI, unsigned OpNum) {} - void printNegZeroOperand(const MCInst *MI, unsigned OpNum) {} + void printCPSOptionOperand(const MCInst *MI, unsigned OpNum); + void printMSRMaskOperand(const MCInst *MI, unsigned OpNum); + void printNegZeroOperand(const MCInst *MI, unsigned OpNum); void printPredicateOperand(const MCInst *MI, unsigned OpNum); void printMandatoryPredicateOperand(const MCInst *MI, unsigned OpNum); void printSBitModifierOperand(const MCInst *MI, unsigned OpNum); @@ -82,10 +82,10 @@ const char *Modifier); void printJTBlockOperand(const MCInst *MI, unsigned OpNum) {} void printJT2BlockOperand(const MCInst *MI, unsigned OpNum) {} - void printTBAddrMode(const MCInst *MI, unsigned OpNum) {} + void printTBAddrMode(const MCInst *MI, unsigned OpNum); void printNoHashImmediate(const MCInst *MI, unsigned OpNum); - void printVFPf32ImmOperand(const MCInst *MI, int OpNum) {} - void printVFPf64ImmOperand(const MCInst *MI, int OpNum) {} + void printVFPf32ImmOperand(const MCInst *MI, unsigned OpNum); + void printVFPf64ImmOperand(const MCInst *MI, unsigned OpNum); void printHex8ImmOperand(const MCInst *MI, int OpNum) {} void printHex16ImmOperand(const MCInst *MI, int OpNum) {} void printHex32ImmOperand(const MCInst *MI, int OpNum) {} Modified: llvm/trunk/test/CodeGen/ARM/2009-10-27-double-align.ll URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/CodeGen/ARM/2009-10-27-double-align.ll?rev=98745&r1=98744&r2=98745&view=diff ============================================================================== --- llvm/trunk/test/CodeGen/ARM/2009-10-27-double-align.ll (original) +++ llvm/trunk/test/CodeGen/ARM/2009-10-27-double-align.ll Wed Mar 17 12:52:21 2010 @@ -4,8 +4,8 @@ define arm_aapcscc void @g() { entry: -;CHECK: [sp, #+8] -;CHECK: [sp, #+12] +;CHECK: [sp, #8] +;CHECK: [sp, #12] ;CHECK: [sp] tail call arm_aapcscc void (i8*, ...)* @f(i8* getelementptr ([1 x i8]* @.str, i32 0, i32 0), i32 1, double 2.000000e+00, i32 3, double 4.000000e+00) ret void Modified: llvm/trunk/test/CodeGen/ARM/2009-10-30.ll URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/CodeGen/ARM/2009-10-30.ll?rev=98745&r1=98744&r2=98745&view=diff ============================================================================== --- llvm/trunk/test/CodeGen/ARM/2009-10-30.ll (original) +++ llvm/trunk/test/CodeGen/ARM/2009-10-30.ll Wed Mar 17 12:52:21 2010 @@ -6,7 +6,7 @@ entry: ;CHECK: sub sp, sp, #4 ;CHECK: add r{{[0-9]+}}, sp, #8 -;CHECK: str r{{[0-9]+}}, [sp], #+4 +;CHECK: str r{{[0-9]+}}, [sp], #4 ;CHECK: bx lr %ap = alloca i8*, align 4 %ap1 = bitcast i8** %ap to i8* Modified: llvm/trunk/test/CodeGen/ARM/arm-negative-stride.ll URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/CodeGen/ARM/arm-negative-stride.ll?rev=98745&r1=98744&r2=98745&view=diff ============================================================================== --- llvm/trunk/test/CodeGen/ARM/arm-negative-stride.ll (original) +++ llvm/trunk/test/CodeGen/ARM/arm-negative-stride.ll Wed Mar 17 12:52:21 2010 @@ -5,7 +5,7 @@ define void @test(i32* %P, i32 %A, i32 %i) nounwind { entry: -; CHECK: str r1, [{{r.*}}, +{{r.*}}, lsl #2] +; CHECK: str r1, [{{r.*}}, {{r.*}}, lsl #2] icmp eq i32 %i, 0 ; :0 [#uses=1] br i1 %0, label %return, label %bb Modified: llvm/trunk/test/CodeGen/ARM/globals.ll URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/CodeGen/ARM/globals.ll?rev=98745&r1=98744&r2=98745&view=diff ============================================================================== --- llvm/trunk/test/CodeGen/ARM/globals.ll (original) +++ llvm/trunk/test/CodeGen/ARM/globals.ll Wed Mar 17 12:52:21 2010 @@ -41,7 +41,7 @@ ; DarwinPIC: _test1: ; DarwinPIC: ldr r0, LCPI1_0 ; DarwinPIC: LPC1_0: -; DarwinPIC: ldr r0, [pc, +r0] +; DarwinPIC: ldr r0, [pc, r0] ; DarwinPIC: ldr r0, [r0] ; DarwinPIC: bx lr @@ -63,7 +63,7 @@ ; LinuxPIC: .LPC1_0: ; LinuxPIC: add r0, pc, r0 -; LinuxPIC: ldr r0, [r1, +r0] +; LinuxPIC: ldr r0, [r1, r0] ; LinuxPIC: ldr r0, [r0] ; LinuxPIC: bx lr Modified: llvm/trunk/test/CodeGen/ARM/ldrd.ll URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/CodeGen/ARM/ldrd.ll?rev=98745&r1=98744&r2=98745&view=diff ============================================================================== --- llvm/trunk/test/CodeGen/ARM/ldrd.ll (original) +++ llvm/trunk/test/CodeGen/ARM/ldrd.ll Wed Mar 17 12:52:21 2010 @@ -10,10 +10,10 @@ ;V6: ldrd r2, [r2] ;V5: ldr r3, [r2] -;V5: ldr r2, [r2, #+4] +;V5: ldr r2, [r2, #4] ;EABI: ldr r3, [r2] -;EABI: ldr r2, [r2, #+4] +;EABI: ldr r2, [r2, #4] %0 = load i64** @b, align 4 %1 = load i64* %0, align 4 Modified: llvm/trunk/test/CodeGen/ARM/str_pre-2.ll URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/CodeGen/ARM/str_pre-2.ll?rev=98745&r1=98744&r2=98745&view=diff ============================================================================== --- llvm/trunk/test/CodeGen/ARM/str_pre-2.ll (original) +++ llvm/trunk/test/CodeGen/ARM/str_pre-2.ll Wed Mar 17 12:52:21 2010 @@ -1,5 +1,5 @@ ; RUN: llc < %s -mtriple=arm-linux-gnu | grep {str.*\\!} -; RUN: llc < %s -mtriple=arm-linux-gnu | grep {ldr.*\\\[.*\], #+4} +; RUN: llc < %s -mtriple=arm-linux-gnu | grep {ldr.*\\\[.*\], #4} @b = external global i64* Modified: llvm/trunk/test/CodeGen/ARM/tls2.ll URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/CodeGen/ARM/tls2.ll?rev=98745&r1=98744&r2=98745&view=diff ============================================================================== --- llvm/trunk/test/CodeGen/ARM/tls2.ll (original) +++ llvm/trunk/test/CodeGen/ARM/tls2.ll Wed Mar 17 12:52:21 2010 @@ -7,7 +7,7 @@ define i32 @f() { ; CHECK-NONPIC: f: -; CHECK-NONPIC: ldr {{r.}}, [pc, +{{r.}}] +; CHECK-NONPIC: ldr {{r.}}, [pc, {{r.}}] ; CHECK-NONPIC: i(gottpoff) ; CHECK-PIC: f: ; CHECK-PIC: __tls_get_addr @@ -18,7 +18,7 @@ define i32* @g() { ; CHECK-NONPIC: g: -; CHECK-NONPIC: ldr {{r.}}, [pc, +{{r.}}] +; CHECK-NONPIC: ldr {{r.}}, [pc, {{r.}}] ; CHECK-NONPIC: i(gottpoff) ; CHECK-PIC: g: ; CHECK-PIC: __tls_get_addr Modified: llvm/trunk/test/CodeGen/Thumb2/ldr-str-imm12.ll URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/CodeGen/Thumb2/ldr-str-imm12.ll?rev=98745&r1=98744&r2=98745&view=diff ============================================================================== --- llvm/trunk/test/CodeGen/Thumb2/ldr-str-imm12.ll (original) +++ llvm/trunk/test/CodeGen/Thumb2/ldr-str-imm12.ll Wed Mar 17 12:52:21 2010 @@ -22,7 +22,7 @@ define arm_apcscc %union.rec* @Manifest(%union.rec* %x, %union.rec* %env, %struct.STYLE* %style, %union.rec** %bthr, %union.rec** %fthr, %union.rec** %target, %union.rec** %crs, i32 %ok, i32 %need_expand, %union.rec** %enclose, i32 %fcr) nounwind { entry: -; CHECK: ldr.w r9, [r7, #+28] +; CHECK: ldr.w r9, [r7, #28] %xgaps.i = alloca [32 x %union.rec*], align 4 ; <[32 x %union.rec*]*> [#uses=0] %ycomp.i = alloca [32 x %union.rec*], align 4 ; <[32 x %union.rec*]*> [#uses=0] br i1 false, label %bb, label %bb20 @@ -50,9 +50,9 @@ bb420: ; preds = %bb20, %bb20 ; CHECK: bb420 ; CHECK: str r{{[0-7]}}, [sp] -; CHECK: str r{{[0-7]}}, [sp, #+4] -; CHECK: str r{{[0-7]}}, [sp, #+8] -; CHECK: str{{(.w)?}} r{{[0-9]+}}, [sp, #+24] +; CHECK: str r{{[0-7]}}, [sp, #4] +; CHECK: str r{{[0-7]}}, [sp, #8] +; CHECK: str{{(.w)?}} r{{[0-9]+}}, [sp, #24] store %union.rec* null, %union.rec** @zz_hold, align 4 store %union.rec* null, %union.rec** @zz_res, align 4 store %union.rec* %x, %union.rec** @zz_hold, align 4 Modified: llvm/trunk/test/CodeGen/Thumb2/thumb2-ldr.ll URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/CodeGen/Thumb2/thumb2-ldr.ll?rev=98745&r1=98744&r2=98745&view=diff ============================================================================== --- llvm/trunk/test/CodeGen/Thumb2/thumb2-ldr.ll (original) +++ llvm/trunk/test/CodeGen/Thumb2/thumb2-ldr.ll Wed Mar 17 12:52:21 2010 @@ -11,7 +11,7 @@ define i32 @f2(i32* %v) { entry: ; CHECK: f2: -; CHECK: ldr.w r0, [r0, #+4092] +; CHECK: ldr.w r0, [r0, #4092] %tmp2 = getelementptr i32* %v, i32 1023 %tmp = load i32* %tmp2 ret i32 %tmp Modified: llvm/trunk/test/CodeGen/Thumb2/thumb2-ldrh.ll URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/CodeGen/Thumb2/thumb2-ldrh.ll?rev=98745&r1=98744&r2=98745&view=diff ============================================================================== --- llvm/trunk/test/CodeGen/Thumb2/thumb2-ldrh.ll (original) +++ llvm/trunk/test/CodeGen/Thumb2/thumb2-ldrh.ll Wed Mar 17 12:52:21 2010 @@ -11,7 +11,7 @@ define i16 @f2(i16* %v) { entry: ; CHECK: f2: -; CHECK: ldrh.w r0, [r0, #+2046] +; CHECK: ldrh.w r0, [r0, #2046] %tmp2 = getelementptr i16* %v, i16 1023 %tmp = load i16* %tmp2 ret i16 %tmp Modified: llvm/trunk/test/CodeGen/Thumb2/thumb2-str.ll URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/CodeGen/Thumb2/thumb2-str.ll?rev=98745&r1=98744&r2=98745&view=diff ============================================================================== --- llvm/trunk/test/CodeGen/Thumb2/thumb2-str.ll (original) +++ llvm/trunk/test/CodeGen/Thumb2/thumb2-str.ll Wed Mar 17 12:52:21 2010 @@ -9,7 +9,7 @@ define i32 @f2(i32 %a, i32* %v) { ; CHECK: f2: -; CHECK: str.w r0, [r1, #+4092] +; CHECK: str.w r0, [r1, #4092] %tmp2 = getelementptr i32* %v, i32 1023 store i32 %a, i32* %tmp2 ret i32 %a Modified: llvm/trunk/test/CodeGen/Thumb2/thumb2-str_pre.ll URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/CodeGen/Thumb2/thumb2-str_pre.ll?rev=98745&r1=98744&r2=98745&view=diff ============================================================================== --- llvm/trunk/test/CodeGen/Thumb2/thumb2-str_pre.ll (original) +++ llvm/trunk/test/CodeGen/Thumb2/thumb2-str_pre.ll Wed Mar 17 12:52:21 2010 @@ -2,7 +2,7 @@ define void @test1(i32* %X, i32* %A, i32** %dest) { ; CHECK: test1 -; CHECK: str r1, [r0, #+16]! +; CHECK: str r1, [r0, #16]! %B = load i32* %A ; [#uses=1] %Y = getelementptr i32* %X, i32 4 ; [#uses=2] store i32 %B, i32* %Y @@ -12,7 +12,7 @@ define i16* @test2(i16* %X, i32* %A) { ; CHECK: test2 -; CHECK: strh r1, [r0, #+8]! +; CHECK: strh r1, [r0, #8]! %B = load i32* %A ; [#uses=1] %Y = getelementptr i16* %X, i32 4 ; [#uses=2] %tmp = trunc i32 %B to i16 ; [#uses=1] Modified: llvm/trunk/test/CodeGen/Thumb2/thumb2-strb.ll URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/CodeGen/Thumb2/thumb2-strb.ll?rev=98745&r1=98744&r2=98745&view=diff ============================================================================== --- llvm/trunk/test/CodeGen/Thumb2/thumb2-strb.ll (original) +++ llvm/trunk/test/CodeGen/Thumb2/thumb2-strb.ll Wed Mar 17 12:52:21 2010 @@ -9,7 +9,7 @@ define i8 @f2(i8 %a, i8* %v) { ; CHECK: f2: -; CHECK: strb.w r0, [r1, #+4092] +; CHECK: strb.w r0, [r1, #4092] %tmp2 = getelementptr i8* %v, i32 4092 store i8 %a, i8* %tmp2 ret i8 %a Modified: llvm/trunk/test/CodeGen/Thumb2/thumb2-strh.ll URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/CodeGen/Thumb2/thumb2-strh.ll?rev=98745&r1=98744&r2=98745&view=diff ============================================================================== --- llvm/trunk/test/CodeGen/Thumb2/thumb2-strh.ll (original) +++ llvm/trunk/test/CodeGen/Thumb2/thumb2-strh.ll Wed Mar 17 12:52:21 2010 @@ -9,7 +9,7 @@ define i16 @f2(i16 %a, i16* %v) { ; CHECK: f2: -; CHECK: strh.w r0, [r1, #+4092] +; CHECK: strh.w r0, [r1, #4092] %tmp2 = getelementptr i16* %v, i32 2046 store i16 %a, i16* %tmp2 ret i16 %a From stuart at apple.com Wed Mar 17 13:03:10 2010 From: stuart at apple.com (Stuart Hastings) Date: Wed, 17 Mar 2010 11:03:10 -0700 Subject: [llvm-commits] [llvm-gcc-4.2] r98728 - /llvm-gcc-4.2/trunk/gcc/llvm-convert.cpp In-Reply-To: <4BA103B3.50404@free.fr> References: <20100317155915.205E22A6C12C@llvm.org> <4BA103B3.50404@free.fr> Message-ID: On Mar 17, 2010, at 9:30 AM, Duncan Sands wrote: > Hi Stuart, > >> Use GCC-specd type when referencing ObjC2 bitfields. Radar 7639995. > > I never understood why llvm-gcc insists on using the "declared type" and > not the gcc layed out bitfield types, which are much more logical from > a low-level point of view. I honestly don't know (you might ask Chris), but I'll speculate: If I reference two one-bit bitfields that lie within one word in memory, but more than one byte apart, then the llvm-gcc habit of referencing both with word references could be plausibly coalesced into one memory reference. But that's just a guess; I haven't constructed a test case to see if that actually happens, and it's not a very high priority right now. FWIW, the bug here was an ObjC2 program that referenced memory outside of the struct. It's clearly illegal, but usually harmless; this time, the Apple "guard malloc" library caught us. :-) stuart From bob.wilson at apple.com Wed Mar 17 13:14:50 2010 From: bob.wilson at apple.com (Bob Wilson) Date: Wed, 17 Mar 2010 11:14:50 -0700 Subject: [llvm-commits] [llvm] r98745 - in /llvm/trunk: lib/Target/ARM/ lib/Target/ARM/AsmPrinter/ test/CodeGen/ARM/ test/CodeGen/Thumb2/ In-Reply-To: <20100317175221.D9A732A6C12C@llvm.org> References: <20100317175221.D9A732A6C12C@llvm.org> Message-ID: <3A6A4021-8594-428A-92A7-EBD7250FBEFD@apple.com> Please do not combine separate patches like this. Omitting the "+" is fine, but that is completely unrelated to your other changes. The changes for NEON sub-formats cross the line (IMO) where they start hurting readability of the .td file. Somehow these need to be factored better. If you need ideas for how to do that, let's talk sometime. What is the getSOImmValOneRotate function for? That doesn't seem to have anything to do with the changes you've described. On Mar 17, 2010, at 10:52 AM, Johnny Chen wrote: > Author: johnny > Date: Wed Mar 17 12:52:21 2010 > New Revision: 98745 > > URL: http://llvm.org/viewvc/llvm-project?rev=98745&view=rev > Log: > Added sub-formats to the NeonI/NeonXI instructions to further refine the NEONFrm > instructions to help disassembly. > > We also changed the output of the addressing modes to omit the '+' from the > assembler syntax #+/- or +/-. See, for example, A8.6.57/58/60. > > And modified test cases to not expect '+' in +reg or #+num. For example, > > ; CHECK: ldr.w r9, [r7, #28] > > Modified: > llvm/trunk/lib/Target/ARM/ARMAddressingModes.h > llvm/trunk/lib/Target/ARM/ARMInstrFormats.td > llvm/trunk/lib/Target/ARM/ARMInstrNEON.td > llvm/trunk/lib/Target/ARM/AsmPrinter/ARMAsmPrinter.cpp > llvm/trunk/lib/Target/ARM/AsmPrinter/ARMInstPrinter.cpp > llvm/trunk/lib/Target/ARM/AsmPrinter/ARMInstPrinter.h > llvm/trunk/test/CodeGen/ARM/2009-10-27-double-align.ll > llvm/trunk/test/CodeGen/ARM/2009-10-30.ll > llvm/trunk/test/CodeGen/ARM/arm-negative-stride.ll > llvm/trunk/test/CodeGen/ARM/globals.ll > llvm/trunk/test/CodeGen/ARM/ldrd.ll > llvm/trunk/test/CodeGen/ARM/str_pre-2.ll > llvm/trunk/test/CodeGen/ARM/tls2.ll > llvm/trunk/test/CodeGen/Thumb2/ldr-str-imm12.ll > llvm/trunk/test/CodeGen/Thumb2/thumb2-ldr.ll > llvm/trunk/test/CodeGen/Thumb2/thumb2-ldrh.ll > llvm/trunk/test/CodeGen/Thumb2/thumb2-str.ll > llvm/trunk/test/CodeGen/Thumb2/thumb2-str_pre.ll > llvm/trunk/test/CodeGen/Thumb2/thumb2-strb.ll > llvm/trunk/test/CodeGen/Thumb2/thumb2-strh.ll > > Modified: llvm/trunk/lib/Target/ARM/ARMAddressingModes.h > URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Target/ARM/ARMAddressingModes.h?rev=98745&r1=98744&r2=98745&view=diff > ============================================================================== > --- llvm/trunk/lib/Target/ARM/ARMAddressingModes.h (original) > +++ llvm/trunk/lib/Target/ARM/ARMAddressingModes.h Wed Mar 17 12:52:21 2010 > @@ -35,6 +35,10 @@ > add = '+', sub = '-' > }; > > + static inline const char *getAddrOpcStr(AddrOpc Op) { > + return Op == sub ? "-" : ""; > + } > + > static inline const char *getShiftOpcStr(ShiftOpc Op) { > switch (Op) { > default: assert(0 && "Unknown shift opc!"); > @@ -127,6 +131,20 @@ > return (Imm >> 8) * 2; > } > > + /// getSOImmValOneRotate - Try to handle Imm with an immediate shifter > + /// operand, computing the rotate amount to use. If this immediate value > + /// cannot be handled with a single shifter-op, return 0. > + static inline unsigned getSOImmValOneRotate(unsigned Imm) { > + // A5.2.4 Constants with multiple encodings > + // The lowest unsigned value of rotation wins! > + for (unsigned R = 1; R <= 15; ++R) > + if ((Imm & rotr32(~255U, 2*R)) == 0) > + return 2*R; > + > + // Failed to find a suitable rotate amount. > + return 0; > + } > + > /// getSOImmValRotate - Try to handle Imm with an immediate shifter operand, > /// computing the rotate amount to use. If this immediate value cannot be > /// handled with a single shifter-op, determine a good rotate amount that will > @@ -179,7 +197,7 @@ > // of zero. > if ((Arg & ~255U) == 0) return Arg; > > - unsigned RotAmt = getSOImmValRotate(Arg); > + unsigned RotAmt = getSOImmValOneRotate(Arg); > > // If this cannot be handled with a single shifter_op, bail out. > if (rotr32(~255U, RotAmt) & Arg) > > Modified: llvm/trunk/lib/Target/ARM/ARMInstrFormats.td > URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Target/ARM/ARMInstrFormats.td?rev=98745&r1=98744&r2=98745&view=diff > ============================================================================== > --- llvm/trunk/lib/Target/ARM/ARMInstrFormats.td (original) > +++ llvm/trunk/lib/Target/ARM/ARMInstrFormats.td Wed Mar 17 12:52:21 2010 > @@ -1464,6 +1464,29 @@ > // ARM NEON Instruction templates. > // > > +// NSFormat specifies further details of a NEON instruction. This is used by > +// the disassembler to classify NEONFrm instructions for disassembly purpose. > +class NSFormat val> { > + bits<5> Value = val; > +} > +def NSFormatNone : NSFormat<0>; > +def VLDSTLaneFrm : NSFormat<1>; > +def VLDSTLaneDblFrm : NSFormat<2>; > +def VLDSTRQFrm : NSFormat<3>; > +def NVdImmFrm : NSFormat<4>; > +def NVdVmImmFrm : NSFormat<5>; > +def NVdVmImmVCVTFrm : NSFormat<6>; > +def NVdVmImmVDupLaneFrm : NSFormat<7>; > +def NVdVmImmVSHLLFrm : NSFormat<8>; > +def NVectorShuffleFrm : NSFormat<9>; > +def NVectorShiftFrm : NSFormat<10>; > +def NVectorShift2Frm : NSFormat<11>; > +def NVdVnVmImmFrm : NSFormat<12>; > +def NVdVnVmImmVectorShiftFrm : NSFormat<13>; > +def NVdVnVmImmVectorExtractFrm : NSFormat<14>; > +def NVdVnVmImmMulScalarFrm : NSFormat<15>; > +def VTBLFrm : NSFormat<16>; > + > class NeonI string opc, string dt, string asm, string cstr, list pattern> > : InstARM { > @@ -1474,6 +1497,8 @@ > !strconcat("\t", asm)); > let Pattern = pattern; > list Predicates = [HasNEON]; > + NSFormat NSF = NSFormatNone; // For disassembly. > + bits<5> NSForm = NSFormatNone.Value; // For disassembly. > } > > // Same as NeonI except it does not have a "data type" specifier. > @@ -1485,6 +1510,8 @@ > let AsmString = !strconcat(!strconcat(opc, "${p}"), !strconcat("\t", asm)); > let Pattern = pattern; > list Predicates = [HasNEON]; > + NSFormat NSF = NSFormatNone; // For disassembly. > + bits<5> NSForm = NSFormatNone.Value; // For disassembly. > } > > class NI @@ -1497,6 +1524,8 @@ > string asm, list pattern> > : NeonXI pattern> { > + let NSF = VLDSTRQFrm; // For disassembly. > + let NSForm = VLDSTRQFrm.Value; // For disassembly. > } > > class NLdSt op21_20, bits<4> op11_8, bits<4> op7_4, > @@ -1509,6 +1538,8 @@ > let Inst{21-20} = op21_20; > let Inst{11-8} = op11_8; > let Inst{7-4} = op7_4; > + let NSF = VLDSTLaneFrm; // For disassembly. > + let NSForm = VLDSTLaneFrm.Value; // For disassembly. > } > > class NDataI @@ -1538,6 +1569,8 @@ > let Inst{6} = op6; > let Inst{5} = op5; > let Inst{4} = op4; > + let NSF = NVdImmFrm; // For disassembly. > + let NSForm = NVdImmFrm.Value; // For disassembly. > } > > // NEON 2 vector register format. > @@ -1553,6 +1586,8 @@ > let Inst{11-7} = op11_7; > let Inst{6} = op6; > let Inst{4} = op4; > + let NSF = NVdVmImmFrm; // For disassembly. > + let NSForm = NVdVmImmFrm.Value; // For disassembly. > } > > // Same as N2V except it doesn't have a datatype suffix. > @@ -1568,6 +1603,8 @@ > let Inst{11-7} = op11_7; > let Inst{6} = op6; > let Inst{4} = op4; > + let NSF = NVdVmImmFrm; // For disassembly. > + let NSForm = NVdVmImmFrm.Value; // For disassembly. > } > > // NEON 2 vector register with immediate. > @@ -1581,6 +1618,8 @@ > let Inst{7} = op7; > let Inst{6} = op6; > let Inst{4} = op4; > + let NSF = NVdVmImmFrm; // For disassembly. > + let NSForm = NVdVmImmFrm.Value; // For disassembly. > } > > // NEON 3 vector register format. > @@ -1594,6 +1633,8 @@ > let Inst{11-8} = op11_8; > let Inst{6} = op6; > let Inst{4} = op4; > + let NSF = NVdVnVmImmFrm; // For disassembly. > + let NSForm = NVdVnVmImmFrm.Value; // For disassembly. > } > > // Same as N3VX except it doesn't have a data type suffix. > @@ -1607,6 +1648,8 @@ > let Inst{11-8} = op11_8; > let Inst{6} = op6; > let Inst{4} = op4; > + let NSF = NVdVnVmImmFrm; // For disassembly. > + let NSForm = NVdVnVmImmFrm.Value; // For disassembly. > } > > // NEON VMOVs between scalar and core registers. > > Modified: llvm/trunk/lib/Target/ARM/ARMInstrNEON.td > URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Target/ARM/ARMInstrNEON.td?rev=98745&r1=98744&r2=98745&view=diff > ============================================================================== > --- llvm/trunk/lib/Target/ARM/ARMInstrNEON.td (original) > +++ llvm/trunk/lib/Target/ARM/ARMInstrNEON.td Wed Mar 17 12:52:21 2010 > @@ -213,7 +213,10 @@ > class VLD2Ddbl op7_4, string OpcodeStr, string Dt> > : NLdSt<0,0b10,0b1001,op7_4, (outs DPR:$dst1, DPR:$dst2), > (ins addrmode6:$addr), IIC_VLD2, > - OpcodeStr, Dt, "\\{$dst1, $dst2\\}, $addr", "", []>; > + OpcodeStr, Dt, "\\{$dst1, $dst2\\}, $addr", "", []> { > + let NSF = VLDSTLaneDblFrm; // For disassembly. > + let NSForm = VLDSTLaneDblFrm.Value; // For disassembly. > +} > > def VLD2d8D : VLD2Ddbl<0b0000, "vld2", "8">; > def VLD2d16D : VLD2Ddbl<0b0100, "vld2", "16">; > @@ -228,7 +231,10 @@ > : NLdSt<0,0b10,0b0101,op7_4, (outs DPR:$dst1, DPR:$dst2, DPR:$dst3, GPR:$wb), > (ins addrmode6:$addr), IIC_VLD3, > OpcodeStr, Dt, "\\{$dst1, $dst2, $dst3\\}, $addr", > - "$addr.addr = $wb", []>; > + "$addr.addr = $wb", []> { > + let NSF = VLDSTLaneDblFrm; // For disassembly. > + let NSForm = VLDSTLaneDblFrm.Value; // For disassembly. > +} > > def VLD3d8 : VLD3D<0b0000, "vld3", "8">; > def VLD3d16 : VLD3D<0b0100, "vld3", "16">; > @@ -260,7 +266,10 @@ > (outs DPR:$dst1, DPR:$dst2, DPR:$dst3, DPR:$dst4, GPR:$wb), > (ins addrmode6:$addr), IIC_VLD4, > OpcodeStr, Dt, "\\{$dst1, $dst2, $dst3, $dst4\\}, $addr", > - "$addr.addr = $wb", []>; > + "$addr.addr = $wb", []> { > + let NSF = VLDSTLaneDblFrm; // For disassembly. > + let NSForm = VLDSTLaneDblFrm.Value; // For disassembly. > +} > > def VLD4d8 : VLD4D<0b0000, "vld4", "8">; > def VLD4d16 : VLD4D<0b0100, "vld4", "16">; > @@ -297,12 +306,28 @@ > def VLD2LNd32 : VLD2LN<0b1001, "vld2", "32"> { let Inst{6} = 0; } > > // vld2 to double-spaced even registers. > -def VLD2LNq16a: VLD2LN<0b0101, "vld2", "16"> { let Inst{5} = 1; } > -def VLD2LNq32a: VLD2LN<0b1001, "vld2", "32"> { let Inst{6} = 1; } > +def VLD2LNq16a: VLD2LN<0b0101, "vld2", "16"> { > + let Inst{5} = 1; > + let NSF = VLDSTLaneDblFrm; // For disassembly. > + let NSForm = VLDSTLaneDblFrm.Value; // For disassembly. > +} > +def VLD2LNq32a: VLD2LN<0b1001, "vld2", "32"> { > + let Inst{6} = 1; > + let NSF = VLDSTLaneDblFrm; // For disassembly. > + let NSForm = VLDSTLaneDblFrm.Value; // For disassembly. > +} > > // vld2 to double-spaced odd registers. > -def VLD2LNq16b: VLD2LN<0b0101, "vld2", "16"> { let Inst{5} = 1; } > -def VLD2LNq32b: VLD2LN<0b1001, "vld2", "32"> { let Inst{6} = 1; } > +def VLD2LNq16b: VLD2LN<0b0101, "vld2", "16"> { > + let Inst{5} = 1; > + let NSF = VLDSTLaneDblFrm; // For disassembly. > + let NSForm = VLDSTLaneDblFrm.Value; // For disassembly. > +} > +def VLD2LNq32b: VLD2LN<0b1001, "vld2", "32"> { > + let Inst{6} = 1; > + let NSF = VLDSTLaneDblFrm; // For disassembly. > + let NSForm = VLDSTLaneDblFrm.Value; // For disassembly. > +} > > // VLD3LN : Vector Load (single 3-element structure to one lane) > class VLD3LN op11_8, string OpcodeStr, string Dt> > @@ -318,7 +343,11 @@ > def VLD3LNd32 : VLD3LN<0b1010, "vld3", "32"> { let Inst{6-4} = 0b000; } > > // vld3 to double-spaced even registers. > -def VLD3LNq16a: VLD3LN<0b0110, "vld3", "16"> { let Inst{5-4} = 0b10; } > +def VLD3LNq16a: VLD3LN<0b0110, "vld3", "16"> { > + let Inst{5-4} = 0b10; > + let NSF = VLDSTLaneDblFrm; // For disassembly. > + let NSForm = VLDSTLaneDblFrm.Value; // For disassembly. > +} > def VLD3LNq32a: VLD3LN<0b1010, "vld3", "32"> { let Inst{6-4} = 0b100; } > > // vld3 to double-spaced odd registers. > @@ -340,12 +369,28 @@ > def VLD4LNd32 : VLD4LN<0b1011, "vld4", "32"> { let Inst{6} = 0; } > > // vld4 to double-spaced even registers. > -def VLD4LNq16a: VLD4LN<0b0111, "vld4", "16"> { let Inst{5} = 1; } > -def VLD4LNq32a: VLD4LN<0b1011, "vld4", "32"> { let Inst{6} = 1; } > +def VLD4LNq16a: VLD4LN<0b0111, "vld4", "16"> { > + let Inst{5} = 1; > + let NSF = VLDSTLaneDblFrm; // For disassembly. > + let NSForm = VLDSTLaneDblFrm.Value; // For disassembly. > +} > +def VLD4LNq32a: VLD4LN<0b1011, "vld4", "32"> { > + let Inst{6} = 1; > + let NSF = VLDSTLaneDblFrm; // For disassembly. > + let NSForm = VLDSTLaneDblFrm.Value; // For disassembly. > +} > > // vld4 to double-spaced odd registers. > -def VLD4LNq16b: VLD4LN<0b0111, "vld4", "16"> { let Inst{5} = 1; } > -def VLD4LNq32b: VLD4LN<0b1011, "vld4", "32"> { let Inst{6} = 1; } > +def VLD4LNq16b: VLD4LN<0b0111, "vld4", "16"> { > + let Inst{5} = 1; > + let NSF = VLDSTLaneDblFrm; // For disassembly. > + let NSForm = VLDSTLaneDblFrm.Value; // For disassembly. > +} > +def VLD4LNq32b: VLD4LN<0b1011, "vld4", "32"> { > + let Inst{6} = 1; > + let NSF = VLDSTLaneDblFrm; // For disassembly. > + let NSForm = VLDSTLaneDblFrm.Value; // For disassembly. > +} > > // VLD1DUP : Vector Load (single element to all lanes) > // VLD2DUP : Vector Load (single 2-element structure to all lanes) > @@ -433,7 +478,10 @@ > class VST2Ddbl op7_4, string OpcodeStr, string Dt> > : NLdSt<0, 0b00, 0b1001, op7_4, (outs), > (ins addrmode6:$addr, DPR:$src1, DPR:$src2), IIC_VST, > - OpcodeStr, Dt, "\\{$src1, $src2\\}, $addr", "", []>; > + OpcodeStr, Dt, "\\{$src1, $src2\\}, $addr", "", []> { > + let NSF = VLDSTLaneDblFrm; // For disassembly. > + let NSForm = VLDSTLaneDblFrm.Value; // For disassembly. > +} > > def VST2d8D : VST2Ddbl<0b0000, "vst2", "8">; > def VST2d16D : VST2Ddbl<0b0100, "vst2", "16">; > @@ -448,7 +496,10 @@ > : NLdSt<0,0b00,0b0101,op7_4, (outs GPR:$wb), > (ins addrmode6:$addr, DPR:$src1, DPR:$src2, DPR:$src3), IIC_VST, > OpcodeStr, Dt, "\\{$src1, $src2, $src3\\}, $addr", > - "$addr.addr = $wb", []>; > + "$addr.addr = $wb", []> { > + let NSF = VLDSTLaneDblFrm; // For disassembly. > + let NSForm = VLDSTLaneDblFrm.Value; // For disassembly. > +} > > def VST3d8 : VST3D<0b0000, "vst3", "8">; > def VST3d16 : VST3D<0b0100, "vst3", "16">; > @@ -478,7 +529,10 @@ > : NLdSt<0,0b00,0b0001,op7_4, (outs GPR:$wb), > (ins addrmode6:$addr, DPR:$src1, DPR:$src2, DPR:$src3, DPR:$src4), > IIC_VST, OpcodeStr, Dt, "\\{$src1, $src2, $src3, $src4\\}, $addr", > - "$addr.addr = $wb", []>; > + "$addr.addr = $wb", []> { > + let NSF = VLDSTLaneDblFrm; // For disassembly. > + let NSForm = VLDSTLaneDblFrm.Value; // For disassembly. > +} > > def VST4d8 : VST4D<0b0000, "vst4", "8">; > def VST4d16 : VST4D<0b0100, "vst4", "16">; > @@ -515,12 +569,28 @@ > def VST2LNd32 : VST2LN<0b1001, "vst2", "32"> { let Inst{6} = 0; } > > // vst2 to double-spaced even registers. > -def VST2LNq16a: VST2LN<0b0101, "vst2", "16"> { let Inst{5} = 1; } > -def VST2LNq32a: VST2LN<0b1001, "vst2", "32"> { let Inst{6} = 1; } > +def VST2LNq16a: VST2LN<0b0101, "vst2", "16"> { > + let Inst{5} = 1; > + let NSF = VLDSTLaneDblFrm; // For disassembly. > + let NSForm = VLDSTLaneDblFrm.Value; // For disassembly. > +} > +def VST2LNq32a: VST2LN<0b1001, "vst2", "32"> { > + let Inst{6} = 1; > + let NSF = VLDSTLaneDblFrm; // For disassembly. > + let NSForm = VLDSTLaneDblFrm.Value; // For disassembly. > +} > > // vst2 to double-spaced odd registers. > -def VST2LNq16b: VST2LN<0b0101, "vst2", "16"> { let Inst{5} = 1; } > -def VST2LNq32b: VST2LN<0b1001, "vst2", "32"> { let Inst{6} = 1; } > +def VST2LNq16b: VST2LN<0b0101, "vst2", "16"> { > + let Inst{5} = 1; > + let NSF = VLDSTLaneDblFrm; // For disassembly. > + let NSForm = VLDSTLaneDblFrm.Value; // For disassembly. > +} > +def VST2LNq32b: VST2LN<0b1001, "vst2", "32"> { > + let Inst{6} = 1; > + let NSF = VLDSTLaneDblFrm; // For disassembly. > + let NSForm = VLDSTLaneDblFrm.Value; // For disassembly. > +} > > // VST3LN : Vector Store (single 3-element structure from one lane) > class VST3LN op11_8, string OpcodeStr, string Dt> > @@ -535,12 +605,28 @@ > def VST3LNd32 : VST3LN<0b1010, "vst3", "32"> { let Inst{6-4} = 0b000; } > > // vst3 to double-spaced even registers. > -def VST3LNq16a: VST3LN<0b0110, "vst3", "16"> { let Inst{5-4} = 0b10; } > -def VST3LNq32a: VST3LN<0b1010, "vst3", "32"> { let Inst{6-4} = 0b100; } > +def VST3LNq16a: VST3LN<0b0110, "vst3", "16"> { > + let Inst{5-4} = 0b10; > + let NSF = VLDSTLaneDblFrm; // For disassembly. > + let NSForm = VLDSTLaneDblFrm.Value; // For disassembly. > +} > +def VST3LNq32a: VST3LN<0b1010, "vst3", "32"> { > + let Inst{6-4} = 0b100; > + let NSF = VLDSTLaneDblFrm; // For disassembly. > + let NSForm = VLDSTLaneDblFrm.Value; // For disassembly. > +} > > // vst3 to double-spaced odd registers. > -def VST3LNq16b: VST3LN<0b0110, "vst3", "16"> { let Inst{5-4} = 0b10; } > -def VST3LNq32b: VST3LN<0b1010, "vst3", "32"> { let Inst{6-4} = 0b100; } > +def VST3LNq16b: VST3LN<0b0110, "vst3", "16"> { > + let Inst{5-4} = 0b10; > + let NSF = VLDSTLaneDblFrm; // For disassembly. > + let NSForm = VLDSTLaneDblFrm.Value; // For disassembly. > +} > +def VST3LNq32b: VST3LN<0b1010, "vst3", "32"> { > + let Inst{6-4} = 0b100; > + let NSF = VLDSTLaneDblFrm; // For disassembly. > + let NSForm = VLDSTLaneDblFrm.Value; // For disassembly. > +} > > // VST4LN : Vector Store (single 4-element structure from one lane) > class VST4LN op11_8, string OpcodeStr, string Dt> > @@ -556,12 +642,28 @@ > def VST4LNd32 : VST4LN<0b1011, "vst4", "32"> { let Inst{6} = 0; } > > // vst4 to double-spaced even registers. > -def VST4LNq16a: VST4LN<0b0111, "vst4", "16"> { let Inst{5} = 1; } > -def VST4LNq32a: VST4LN<0b1011, "vst4", "32"> { let Inst{6} = 1; } > +def VST4LNq16a: VST4LN<0b0111, "vst4", "16"> { > + let Inst{5} = 1; > + let NSF = VLDSTLaneDblFrm; // For disassembly. > + let NSForm = VLDSTLaneDblFrm.Value; // For disassembly. > +} > +def VST4LNq32a: VST4LN<0b1011, "vst4", "32"> { > + let Inst{6} = 1; > + let NSF = VLDSTLaneDblFrm; // For disassembly. > + let NSForm = VLDSTLaneDblFrm.Value; // For disassembly. > +} > > // vst4 to double-spaced odd registers. > -def VST4LNq16b: VST4LN<0b0111, "vst4", "16"> { let Inst{5} = 1; } > -def VST4LNq32b: VST4LN<0b1011, "vst4", "32"> { let Inst{6} = 1; } > +def VST4LNq16b: VST4LN<0b0111, "vst4", "16"> { > + let Inst{5} = 1; > + let NSF = VLDSTLaneDblFrm; // For disassembly. > + let NSForm = VLDSTLaneDblFrm.Value; // For disassembly. > +} > +def VST4LNq32b: VST4LN<0b1011, "vst4", "32"> { > + let Inst{6} = 1; > + let NSF = VLDSTLaneDblFrm; // For disassembly. > + let NSForm = VLDSTLaneDblFrm.Value; // For disassembly. > +} > > } // mayStore = 1, hasExtraSrcRegAllocReq = 1 > > @@ -668,12 +770,18 @@ > : N2V<0b11, 0b11, op19_18, 0b10, op11_7, 0, 0, (outs DPR:$dst1, DPR:$dst2), > (ins DPR:$src1, DPR:$src2), IIC_VPERMD, > OpcodeStr, Dt, "$dst1, $dst2", > - "$src1 = $dst1, $src2 = $dst2", []>; > + "$src1 = $dst1, $src2 = $dst2", []> { > + let NSF = NVectorShuffleFrm; // For disassembly. > + let NSForm = NVectorShuffleFrm.Value; // For disassembly. > +} > class N2VQShuffle op19_18, bits<5> op11_7, > InstrItinClass itin, string OpcodeStr, string Dt> > : N2V<0b11, 0b11, op19_18, 0b10, op11_7, 1, 0, (outs QPR:$dst1, QPR:$dst2), > (ins QPR:$src1, QPR:$src2), itin, OpcodeStr, Dt, "$dst1, $dst2", > - "$src1 = $dst1, $src2 = $dst2", []>; > + "$src1 = $dst1, $src2 = $dst2", []> { > + let NSF = NVectorShuffleFrm; // For disassembly. > + let NSForm = NVectorShuffleFrm.Value; // For disassembly. > +} > > // Basic 3-register operations: single-, double- and quad-register. > class N3VS op21_20, bits<4> op11_8, bit op4, > @@ -715,6 +823,8 @@ > (Ty (ShOp (Ty DPR:$src1), > (Ty (NEONvduplane (Ty DPR_VFP2:$src2), imm:$lane)))))]>{ > let isCommutable = 0; > + let NSF = NVdVnVmImmMulScalarFrm; // For disassembly. > + let NSForm = NVdVnVmImmMulScalarFrm.Value; // For disassembly. > } > class N3VDSL16 op21_20, bits<4> op11_8, > string OpcodeStr, string Dt, ValueType Ty, SDNode ShOp> > @@ -725,6 +835,8 @@ > (Ty (ShOp (Ty DPR:$src1), > (Ty (NEONvduplane (Ty DPR_8:$src2), imm:$lane)))))]> { > let isCommutable = 0; > + let NSF = NVdVnVmImmMulScalarFrm; // For disassembly. > + let NSForm = NVdVnVmImmMulScalarFrm.Value; // For disassembly. > } > > class N3VQ op21_20, bits<4> op11_8, bit op4, > @@ -756,6 +868,8 @@ > (ResTy (NEONvduplane (OpTy DPR_VFP2:$src2), > imm:$lane)))))]> { > let isCommutable = 0; > + let NSF = NVdVnVmImmMulScalarFrm; // For disassembly. > + let NSForm = NVdVnVmImmMulScalarFrm.Value; // For disassembly. > } > class N3VQSL16 op21_20, bits<4> op11_8, string OpcodeStr, string Dt, > ValueType ResTy, ValueType OpTy, SDNode ShOp> > @@ -767,6 +881,8 @@ > (ResTy (NEONvduplane (OpTy DPR_8:$src2), > imm:$lane)))))]> { > let isCommutable = 0; > + let NSF = NVdVnVmImmMulScalarFrm; // For disassembly. > + let NSForm = NVdVnVmImmMulScalarFrm.Value; // For disassembly. > } > > // Basic 3-register intrinsics, both double- and quad-register. > @@ -789,6 +905,8 @@ > (Ty (NEONvduplane (Ty DPR_VFP2:$src2), > imm:$lane)))))]> { > let isCommutable = 0; > + let NSF = NVdVnVmImmMulScalarFrm; // For disassembly. > + let NSForm = NVdVnVmImmMulScalarFrm.Value; // For disassembly. > } > class N3VDIntSL16 op21_20, bits<4> op11_8, InstrItinClass itin, > string OpcodeStr, string Dt, ValueType Ty, Intrinsic IntOp> > @@ -800,6 +918,8 @@ > (Ty (NEONvduplane (Ty DPR_8:$src2), > imm:$lane)))))]> { > let isCommutable = 0; > + let NSF = NVdVnVmImmMulScalarFrm; // For disassembly. > + let NSForm = NVdVnVmImmMulScalarFrm.Value; // For disassembly. > } > > class N3VQInt op21_20, bits<4> op11_8, bit op4, > @@ -822,6 +942,8 @@ > (ResTy (NEONvduplane (OpTy DPR_VFP2:$src2), > imm:$lane)))))]> { > let isCommutable = 0; > + let NSF = NVdVnVmImmMulScalarFrm; // For disassembly. > + let NSForm = NVdVnVmImmMulScalarFrm.Value; // For disassembly. > } > class N3VQIntSL16 op21_20, bits<4> op11_8, InstrItinClass itin, > string OpcodeStr, string Dt, > @@ -834,6 +956,8 @@ > (ResTy (NEONvduplane (OpTy DPR_8:$src2), > imm:$lane)))))]> { > let isCommutable = 0; > + let NSF = NVdVnVmImmMulScalarFrm; // For disassembly. > + let NSForm = NVdVnVmImmMulScalarFrm.Value; // For disassembly. > } > > // Multiply-Add/Sub operations: single-, double- and quad-register. > @@ -864,7 +988,10 @@ > (Ty (ShOp (Ty DPR:$src1), > (Ty (MulOp DPR:$src2, > (Ty (NEONvduplane (Ty DPR_VFP2:$src3), > - imm:$lane)))))))]>; > + imm:$lane)))))))]> { > + let NSF = NVdVnVmImmMulScalarFrm; // For disassembly. > + let NSForm = NVdVnVmImmMulScalarFrm.Value; // For disassembly. > +} > class N3VDMulOpSL16 op21_20, bits<4> op11_8, InstrItinClass itin, > string OpcodeStr, string Dt, > ValueType Ty, SDNode MulOp, SDNode ShOp> > @@ -876,7 +1003,10 @@ > (Ty (ShOp (Ty DPR:$src1), > (Ty (MulOp DPR:$src2, > (Ty (NEONvduplane (Ty DPR_8:$src3), > - imm:$lane)))))))]>; > + imm:$lane)))))))]> { > + let NSF = NVdVnVmImmMulScalarFrm; // For disassembly. > + let NSForm = NVdVnVmImmMulScalarFrm.Value; // For disassembly. > +} > > class N3VQMulOp op21_20, bits<4> op11_8, bit op4, > InstrItinClass itin, string OpcodeStr, string Dt, ValueType Ty, > @@ -897,7 +1027,10 @@ > (ResTy (ShOp (ResTy QPR:$src1), > (ResTy (MulOp QPR:$src2, > (ResTy (NEONvduplane (OpTy DPR_VFP2:$src3), > - imm:$lane)))))))]>; > + imm:$lane)))))))]> { > + let NSF = NVdVnVmImmMulScalarFrm; // For disassembly. > + let NSForm = NVdVnVmImmMulScalarFrm.Value; // For disassembly. > +} > class N3VQMulOpSL16 op21_20, bits<4> op11_8, InstrItinClass itin, > string OpcodeStr, string Dt, > ValueType ResTy, ValueType OpTy, > @@ -910,7 +1043,10 @@ > (ResTy (ShOp (ResTy QPR:$src1), > (ResTy (MulOp QPR:$src2, > (ResTy (NEONvduplane (OpTy DPR_8:$src3), > - imm:$lane)))))))]>; > + imm:$lane)))))))]> { > + let NSF = NVdVnVmImmMulScalarFrm; // For disassembly. > + let NSForm = NVdVnVmImmMulScalarFrm.Value; // For disassembly. > +} > > // Neon 3-argument intrinsics, both double- and quad-register. > // The destination register is also used as the first source operand register. > @@ -996,7 +1132,10 @@ > [(set (ResTy QPR:$dst), > (ResTy (IntOp (OpTy DPR:$src1), > (OpTy (NEONvduplane (OpTy DPR_VFP2:$src2), > - imm:$lane)))))]>; > + imm:$lane)))))]> { > + let NSF = NVdVnVmImmMulScalarFrm; // For disassembly. > + let NSForm = NVdVnVmImmMulScalarFrm.Value; // For disassembly. > +} > class N3VLIntSL16 op21_20, bits<4> op11_8, > InstrItinClass itin, string OpcodeStr, string Dt, > ValueType ResTy, ValueType OpTy, Intrinsic IntOp> > @@ -1006,7 +1145,10 @@ > [(set (ResTy QPR:$dst), > (ResTy (IntOp (OpTy DPR:$src1), > (OpTy (NEONvduplane (OpTy DPR_8:$src2), > - imm:$lane)))))]>; > + imm:$lane)))))]> { > + let NSF = NVdVnVmImmMulScalarFrm; // For disassembly. > + let NSForm = NVdVnVmImmMulScalarFrm.Value; // For disassembly. > +} > > // Wide 3-register intrinsics. > class N3VWInt op21_20, bits<4> op11_8, bit op4, > @@ -1055,6 +1197,10 @@ > OpcodeStr, Dt, "$dst, $src2", "$src1 = $dst", > [(set QPR:$dst, (ResTy (IntOp (ResTy QPR:$src1), (OpTy QPR:$src2))))]>; > > +// This is a big let * in block to mark these instructions NVectorShiftFrm to > +// help the disassembler. > +let NSF = NVectorShiftFrm, NSForm = NVectorShiftFrm.Value in { > + > // Shift by immediate, > // both double- and quad-register. > class N2VDSh op11_8, bit op7, bit op4, > @@ -1072,16 +1218,6 @@ > OpcodeStr, Dt, "$dst, $src, $SIMM", "", > [(set QPR:$dst, (Ty (OpNode (Ty QPR:$src), (i32 imm:$SIMM))))]>; > > -// Long shift by immediate. > -class N2VLSh op11_8, bit op7, bit op6, bit op4, > - string OpcodeStr, string Dt, > - ValueType ResTy, ValueType OpTy, SDNode OpNode> > - : N2VImm - (outs QPR:$dst), (ins DPR:$src, i32imm:$SIMM), IIC_VSHLiD, > - OpcodeStr, Dt, "$dst, $src, $SIMM", "", > - [(set QPR:$dst, (ResTy (OpNode (OpTy DPR:$src), > - (i32 imm:$SIMM))))]>; > - > // Narrow shift by immediate. > class N2VNSh op11_8, bit op7, bit op6, bit op4, > InstrItinClass itin, string OpcodeStr, string Dt, > @@ -1124,8 +1260,26 @@ > OpcodeStr, Dt, "$dst, $src2, $SIMM", "$src1 = $dst", > [(set QPR:$dst, (Ty (ShOp QPR:$src1, QPR:$src2, (i32 imm:$SIMM))))]>; > > +} // End of "let NSF = NVectorShiftFrm, ..." > + > +// Long shift by immediate. > +class N2VLSh op11_8, bit op7, bit op6, bit op4, > + string OpcodeStr, string Dt, > + ValueType ResTy, ValueType OpTy, SDNode OpNode> > + : N2VImm + (outs QPR:$dst), (ins DPR:$src, i32imm:$SIMM), IIC_VSHLiD, > + OpcodeStr, Dt, "$dst, $src, $SIMM", "", > + [(set QPR:$dst, (ResTy (OpNode (OpTy DPR:$src), > + (i32 imm:$SIMM))))]> { > + // This has a different interpretation of the shift amount encoding than > + // NVectorShiftFrm. > + let NSF = NVectorShift2Frm; // For disassembly. > + let NSForm = NVectorShift2Frm.Value; // For disassembly. > +} > + > // Convert, with fractional bits immediate, > // both double- and quad-register. > +let NSF = NVdVmImmVCVTFrm, NSForm = NVdVmImmVCVTFrm.Value in { > class N2VCvtD op11_8, bit op7, bit op4, > string OpcodeStr, string Dt, ValueType ResTy, ValueType OpTy, > Intrinsic IntOp> > @@ -1140,6 +1294,7 @@ > (outs QPR:$dst), (ins QPR:$src, i32imm:$SIMM), IIC_VUNAQ, > OpcodeStr, Dt, "$dst, $src, $SIMM", "", > [(set QPR:$dst, (ResTy (IntOp (OpTy QPR:$src), (i32 imm:$SIMM))))]>; > +} > > //===----------------------------------------------------------------------===// > // Multiclasses > @@ -1350,6 +1505,60 @@ > v2i64, v2i64, IntOp, Commutable>; > } > > +// Same as N3VInt_QHSD, except they're for Vector Shift (Register) Instructions. > +// D:Vd M:Vm N:Vn (notice that M:Vm is the first operand) > +// This helps the disassembler. > +let NSF = NVdVnVmImmVectorShiftFrm, NSForm = NVdVnVmImmVectorShiftFrm.Value in { > +multiclass N3VInt_HS2 op11_8, bit op4, > + InstrItinClass itinD16, InstrItinClass itinD32, > + InstrItinClass itinQ16, InstrItinClass itinQ32, > + string OpcodeStr, string Dt, > + Intrinsic IntOp, bit Commutable = 0> { > + // 64-bit vector types. > + def v4i16 : N3VDInt + OpcodeStr, !strconcat(Dt, "16"), > + v4i16, v4i16, IntOp, Commutable>; > + def v2i32 : N3VDInt + OpcodeStr, !strconcat(Dt, "32"), > + v2i32, v2i32, IntOp, Commutable>; > + > + // 128-bit vector types. > + def v8i16 : N3VQInt + OpcodeStr, !strconcat(Dt, "16"), > + v8i16, v8i16, IntOp, Commutable>; > + def v4i32 : N3VQInt + OpcodeStr, !strconcat(Dt, "32"), > + v4i32, v4i32, IntOp, Commutable>; > +} > +multiclass N3VInt_QHS2 op11_8, bit op4, > + InstrItinClass itinD16, InstrItinClass itinD32, > + InstrItinClass itinQ16, InstrItinClass itinQ32, > + string OpcodeStr, string Dt, > + Intrinsic IntOp, bit Commutable = 0> > + : N3VInt_HS2 + OpcodeStr, Dt, IntOp, Commutable> { > + def v8i8 : N3VDInt + OpcodeStr, !strconcat(Dt, "8"), > + v8i8, v8i8, IntOp, Commutable>; > + def v16i8 : N3VQInt + OpcodeStr, !strconcat(Dt, "8"), > + v16i8, v16i8, IntOp, Commutable>; > +} > +multiclass N3VInt_QHSD2 op11_8, bit op4, > + InstrItinClass itinD16, InstrItinClass itinD32, > + InstrItinClass itinQ16, InstrItinClass itinQ32, > + string OpcodeStr, string Dt, > + Intrinsic IntOp, bit Commutable = 0> > + : N3VInt_QHS2 + OpcodeStr, Dt, IntOp, Commutable> { > + def v1i64 : N3VDInt + OpcodeStr, !strconcat(Dt, "64"), > + v1i64, v1i64, IntOp, Commutable>; > + def v2i64 : N3VQInt + OpcodeStr, !strconcat(Dt, "64"), > + v2i64, v2i64, IntOp, Commutable>; > +} > +} > > // Neon Narrowing 3-register vector intrinsics, > // source operand element sizes of 16, 32 and 64 bits: > @@ -1619,6 +1828,47 @@ > // imm6 = xxxxxx > } > > +// Same as N2VSh_QHSD, except the instructions have a differnt interpretation of > +// the shift amount. This helps the disassembler. > +let NSF = NVectorShift2Frm, NSForm = NVectorShift2Frm.Value in { > +multiclass N2VSh_QHSD2 op11_8, bit op4, > + InstrItinClass itin, string OpcodeStr, string Dt, > + SDNode OpNode> { > + // 64-bit vector types. > + def v8i8 : N2VDSh + OpcodeStr, !strconcat(Dt, "8"), v8i8, OpNode> { > + let Inst{21-19} = 0b001; // imm6 = 001xxx > + } > + def v4i16 : N2VDSh + OpcodeStr, !strconcat(Dt, "16"), v4i16, OpNode> { > + let Inst{21-20} = 0b01; // imm6 = 01xxxx > + } > + def v2i32 : N2VDSh + OpcodeStr, !strconcat(Dt, "32"), v2i32, OpNode> { > + let Inst{21} = 0b1; // imm6 = 1xxxxx > + } > + def v1i64 : N2VDSh + OpcodeStr, !strconcat(Dt, "64"), v1i64, OpNode>; > + // imm6 = xxxxxx > + > + // 128-bit vector types. > + def v16i8 : N2VQSh + OpcodeStr, !strconcat(Dt, "8"), v16i8, OpNode> { > + let Inst{21-19} = 0b001; // imm6 = 001xxx > + } > + def v8i16 : N2VQSh + OpcodeStr, !strconcat(Dt, "16"), v8i16, OpNode> { > + let Inst{21-20} = 0b01; // imm6 = 01xxxx > + } > + def v4i32 : N2VQSh + OpcodeStr, !strconcat(Dt, "32"), v4i32, OpNode> { > + let Inst{21} = 0b1; // imm6 = 1xxxxx > + } > + def v2i64 : N2VQSh + OpcodeStr, !strconcat(Dt, "64"), v2i64, OpNode>; > + // imm6 = xxxxxx > +} > +} > > // Neon Shift-Accumulate vector operations, > // element sizes of 8, 16, 32 and 64 bits: > @@ -1699,6 +1949,47 @@ > // imm6 = xxxxxx > } > > +// Same as N2VShIns_QHSD, except the instructions have a differnt interpretation > +// of the shift amount. This helps the disassembler. > +let NSF = NVectorShift2Frm, NSForm = NVectorShift2Frm.Value in { > +multiclass N2VShIns_QHSD2 op11_8, bit op4, > + string OpcodeStr, SDNode ShOp> { > + // 64-bit vector types. > + def v8i8 : N2VDShIns + OpcodeStr, "8", v8i8, ShOp> { > + let Inst{21-19} = 0b001; // imm6 = 001xxx > + } > + def v4i16 : N2VDShIns + OpcodeStr, "16", v4i16, ShOp> { > + let Inst{21-20} = 0b01; // imm6 = 01xxxx > + } > + def v2i32 : N2VDShIns + OpcodeStr, "32", v2i32, ShOp> { > + let Inst{21} = 0b1; // imm6 = 1xxxxx > + } > + def v1i64 : N2VDShIns + OpcodeStr, "64", v1i64, ShOp>; > + // imm6 = xxxxxx > + > + // 128-bit vector types. > + def v16i8 : N2VQShIns + OpcodeStr, "8", v16i8, ShOp> { > + let Inst{21-19} = 0b001; // imm6 = 001xxx > + } > + def v8i16 : N2VQShIns + OpcodeStr, "16", v8i16, ShOp> { > + let Inst{21-20} = 0b01; // imm6 = 01xxxx > + } > + def v4i32 : N2VQShIns + OpcodeStr, "32", v4i32, ShOp> { > + let Inst{21} = 0b1; // imm6 = 1xxxxx > + } > + def v2i64 : N2VQShIns + OpcodeStr, "64", v2i64, ShOp>; > + // imm6 = xxxxxx > +} > +} > + > // Neon Shift Long operations, > // element sizes of 8, 16, 32 bits: > multiclass N2VLSh_QHS op11_8, bit op7, bit op6, > @@ -2329,18 +2620,21 @@ > // Vector Shifts. > > // VSHL : Vector Shift > -defm VSHLs : N3VInt_QHSD<0, 0, 0b0100, 0, IIC_VSHLiD, IIC_VSHLiD, IIC_VSHLiQ, > - IIC_VSHLiQ, "vshl", "s", int_arm_neon_vshifts, 0>; > -defm VSHLu : N3VInt_QHSD<1, 0, 0b0100, 0, IIC_VSHLiD, IIC_VSHLiD, IIC_VSHLiQ, > - IIC_VSHLiQ, "vshl", "u", int_arm_neon_vshiftu, 0>; > +defm VSHLs : N3VInt_QHSD2<0,0, 0b0100, 0, IIC_VSHLiD, IIC_VSHLiD, IIC_VSHLiQ, > + IIC_VSHLiQ, "vshl", "s", int_arm_neon_vshifts, 0>; > +defm VSHLu : N3VInt_QHSD2<1,0, 0b0100, 0, IIC_VSHLiD, IIC_VSHLiD, IIC_VSHLiQ, > + IIC_VSHLiQ, "vshl", "u", int_arm_neon_vshiftu, 0>; > // VSHL : Vector Shift Left (Immediate) > -defm VSHLi : N2VSh_QHSD<0, 1, 0b0101, 1, IIC_VSHLiD, "vshl", "i", NEONvshl>; > +// (disassembly note: this has a different interpretation of the shift amont) > +defm VSHLi : N2VSh_QHSD2<0, 1, 0b0101, 1, IIC_VSHLiD, "vshl", "i", NEONvshl>; > // VSHR : Vector Shift Right (Immediate) > defm VSHRs : N2VSh_QHSD<0, 1, 0b0000, 1, IIC_VSHLiD, "vshr", "s", NEONvshrs>; > defm VSHRu : N2VSh_QHSD<1, 1, 0b0000, 1, IIC_VSHLiD, "vshr", "u", NEONvshru>; > > // VSHLL : Vector Shift Left Long > +// (disassembly note: this has a different interpretation of the shift amont) > defm VSHLLs : N2VLSh_QHS<0, 1, 0b1010, 0, 0, 1, "vshll", "s", NEONvshlls>; > +// (disassembly note: this has a different interpretation of the shift amont) > defm VSHLLu : N2VLSh_QHS<1, 1, 0b1010, 0, 0, 1, "vshll", "u", NEONvshllu>; > > // VSHLL : Vector Shift Left Long (with maximum shift count) > @@ -2350,6 +2644,8 @@ > : N2VLSh ResTy, OpTy, OpNode> { > let Inst{21-16} = op21_16; > + let NSF = NVdVmImmVSHLLFrm; // For disassembly. > + let NSForm = NVdVmImmVSHLLFrm.Value; // For disassembly. > } > def VSHLLi8 : N2VLShMax<1, 1, 0b110010, 0b0011, 0, 0, 0, "vshll", "i8", > v8i16, v8i8, NEONvshlli>; > @@ -2363,10 +2659,10 @@ > NEONvshrn>; > > // VRSHL : Vector Rounding Shift > -defm VRSHLs : N3VInt_QHSD<0,0,0b0101,0, IIC_VSHLi4D, IIC_VSHLi4D, IIC_VSHLi4Q, > - IIC_VSHLi4Q, "vrshl", "s", int_arm_neon_vrshifts,0>; > -defm VRSHLu : N3VInt_QHSD<1,0,0b0101,0, IIC_VSHLi4D, IIC_VSHLi4D, IIC_VSHLi4Q, > - IIC_VSHLi4Q, "vrshl", "u", int_arm_neon_vrshiftu,0>; > +defm VRSHLs : N3VInt_QHSD2<0,0,0b0101,0,IIC_VSHLi4D, IIC_VSHLi4D, IIC_VSHLi4Q, > + IIC_VSHLi4Q,"vrshl", "s", int_arm_neon_vrshifts,0>; > +defm VRSHLu : N3VInt_QHSD2<1,0,0b0101,0,IIC_VSHLi4D, IIC_VSHLi4D, IIC_VSHLi4Q, > + IIC_VSHLi4Q,"vrshl", "u", int_arm_neon_vrshiftu,0>; > // VRSHR : Vector Rounding Shift Right > defm VRSHRs : N2VSh_QHSD<0,1,0b0010,1, IIC_VSHLi4D, "vrshr", "s", NEONvrshrs>; > defm VRSHRu : N2VSh_QHSD<1,1,0b0010,1, IIC_VSHLi4D, "vrshr", "u", NEONvrshru>; > @@ -2376,15 +2672,18 @@ > NEONvrshrn>; > > // VQSHL : Vector Saturating Shift > -defm VQSHLs : N3VInt_QHSD<0,0,0b0100,1, IIC_VSHLi4D, IIC_VSHLi4D, IIC_VSHLi4Q, > - IIC_VSHLi4Q, "vqshl", "s", int_arm_neon_vqshifts,0>; > -defm VQSHLu : N3VInt_QHSD<1,0,0b0100,1, IIC_VSHLi4D, IIC_VSHLi4D, IIC_VSHLi4Q, > - IIC_VSHLi4Q, "vqshl", "u", int_arm_neon_vqshiftu,0>; > +defm VQSHLs : N3VInt_QHSD2<0,0,0b0100,1,IIC_VSHLi4D, IIC_VSHLi4D, IIC_VSHLi4Q, > + IIC_VSHLi4Q, "vqshl", "s", int_arm_neon_vqshifts,0>; > +defm VQSHLu : N3VInt_QHSD2<1,0,0b0100,1,IIC_VSHLi4D, IIC_VSHLi4D, IIC_VSHLi4Q, > + IIC_VSHLi4Q, "vqshl", "u", int_arm_neon_vqshiftu,0>; > // VQSHL : Vector Saturating Shift Left (Immediate) > -defm VQSHLsi : N2VSh_QHSD<0,1,0b0111,1, IIC_VSHLi4D, "vqshl", "s", NEONvqshls>; > -defm VQSHLui : N2VSh_QHSD<1,1,0b0111,1, IIC_VSHLi4D, "vqshl", "u", NEONvqshlu>; > +// (disassembly note: this has a different interpretation of the shift amont) > +defm VQSHLsi : N2VSh_QHSD2<0,1,0b0111,1, IIC_VSHLi4D, "vqshl", "s", NEONvqshls>; > +// (disassembly note: this has a different interpretation of the shift amont) > +defm VQSHLui : N2VSh_QHSD2<1,1,0b0111,1, IIC_VSHLi4D, "vqshl", "u", NEONvqshlu>; > // VQSHLU : Vector Saturating Shift Left (Immediate, Unsigned) > -defm VQSHLsu : N2VSh_QHSD<1,1,0b0110,1, IIC_VSHLi4D, "vqshlu","s",NEONvqshlsu>; > +// (disassembly note: this has a different interpretation of the shift amont) > +defm VQSHLsu : N2VSh_QHSD2<1,1,0b0110,1, IIC_VSHLi4D, "vqshlu","s",NEONvqshlsu>; > > // VQSHRN : Vector Saturating Shift Right and Narrow > defm VQSHRNs : N2VNSh_HSD<0, 1, 0b1001, 0, 0, 1, IIC_VSHLi4D, "vqshrn", "s", > @@ -2397,12 +2696,12 @@ > NEONvqshrnsu>; > > // VQRSHL : Vector Saturating Rounding Shift > -defm VQRSHLs : N3VInt_QHSD<0,0,0b0101,1, IIC_VSHLi4D, IIC_VSHLi4D, IIC_VSHLi4Q, > - IIC_VSHLi4Q, "vqrshl", "s", > - int_arm_neon_vqrshifts, 0>; > -defm VQRSHLu : N3VInt_QHSD<1,0,0b0101,1, IIC_VSHLi4D, IIC_VSHLi4D, IIC_VSHLi4Q, > - IIC_VSHLi4Q, "vqrshl", "u", > - int_arm_neon_vqrshiftu, 0>; > +defm VQRSHLs : N3VInt_QHSD2<0,0,0b0101,1, IIC_VSHLi4D, IIC_VSHLi4D, IIC_VSHLi4Q, > + IIC_VSHLi4Q, "vqrshl", "s", > + int_arm_neon_vqrshifts, 0>; > +defm VQRSHLu : N3VInt_QHSD2<1,0,0b0101,1, IIC_VSHLi4D, IIC_VSHLi4D, IIC_VSHLi4Q, > + IIC_VSHLi4Q, "vqrshl", "u", > + int_arm_neon_vqrshiftu, 0>; > > // VQRSHRN : Vector Saturating Rounding Shift Right and Narrow > defm VQRSHRNs : N2VNSh_HSD<0, 1, 0b1001, 0, 1, 1, IIC_VSHLi4D, "vqrshrn", "s", > @@ -2422,7 +2721,8 @@ > defm VRSRAu : N2VShAdd_QHSD<1, 1, 0b0011, 1, "vrsra", "u", NEONvrshru>; > > // VSLI : Vector Shift Left and Insert > -defm VSLI : N2VShIns_QHSD<1, 1, 0b0101, 1, "vsli", NEONvsli>; > +// (disassembly note: this has a different interpretation of the shift amont) > +defm VSLI : N2VShIns_QHSD2<1, 1, 0b0101, 1, "vsli", NEONvsli>; > // VSRI : Vector Shift Right and Insert > defm VSRI : N2VShIns_QHSD<1, 1, 0b0100, 1, "vsri", NEONvsri>; > > @@ -2518,10 +2818,13 @@ > > // VMOV : Vector Move (Register) > > +// Mark these instructions as 2-register instructions to help the disassembler. > +let NSF = NVdVmImmFrm, NSForm = NVdVmImmFrm.Value in { > def VMOVDneon: N3VX<0, 0, 0b10, 0b0001, 0, 1, (outs DPR:$dst), (ins DPR:$src), > IIC_VMOVD, "vmov", "$dst, $src", "", []>; > def VMOVQ : N3VX<0, 0, 0b10, 0b0001, 1, 1, (outs QPR:$dst), (ins QPR:$src), > IIC_VMOVD, "vmov", "$dst, $src", "", []>; > +} > > // VMOV : Vector Move (Immediate) > > @@ -2762,6 +3065,7 @@ > > // VDUP : Vector Duplicate Lane (from scalar to all elements) > > +let NSF = NVdVmImmVDupLaneFrm, NSForm = NVdVmImmVDupLaneFrm.Value in { > class VDUPLND op19_18, bits<2> op17_16, > string OpcodeStr, string Dt, ValueType Ty> > : N2V<0b11, 0b11, op19_18, op17_16, 0b11000, 0, 0, > @@ -2775,6 +3079,7 @@ > (outs QPR:$dst), (ins DPR:$src, nohash_imm:$lane), IIC_VMOVD, > OpcodeStr, Dt, "$dst, $src[$lane]", "", > [(set QPR:$dst, (ResTy (NEONvduplane (OpTy DPR:$src), imm:$lane)))]>; > +} > > // Inst{19-16} is partially specified depending on the element size. > > @@ -2843,24 +3148,37 @@ > > // Vector Conversions. > > +let NSF = NVdVmImmVCVTFrm, NSForm = NVdVmImmVCVTFrm.Value in { > +class N2VDX op24_23, bits<2> op21_20, bits<2> op19_18, > + bits<2> op17_16, bits<5> op11_7, bit op4, string OpcodeStr, > + string Dt, ValueType ResTy, ValueType OpTy, SDNode OpNode> > + : N2VD + ResTy, OpTy, OpNode>; > +class N2VQX op24_23, bits<2> op21_20, bits<2> op19_18, > + bits<2> op17_16, bits<5> op11_7, bit op4, string OpcodeStr, > + string Dt, ValueType ResTy, ValueType OpTy, SDNode OpNode> > + : N2VQ + ResTy, OpTy, OpNode>; > +} > + > // VCVT : Vector Convert Between Floating-Point and Integers > -def VCVTf2sd : N2VD<0b11, 0b11, 0b10, 0b11, 0b01110, 0, "vcvt", "s32.f32", > - v2i32, v2f32, fp_to_sint>; > -def VCVTf2ud : N2VD<0b11, 0b11, 0b10, 0b11, 0b01111, 0, "vcvt", "u32.f32", > - v2i32, v2f32, fp_to_uint>; > -def VCVTs2fd : N2VD<0b11, 0b11, 0b10, 0b11, 0b01100, 0, "vcvt", "f32.s32", > - v2f32, v2i32, sint_to_fp>; > -def VCVTu2fd : N2VD<0b11, 0b11, 0b10, 0b11, 0b01101, 0, "vcvt", "f32.u32", > - v2f32, v2i32, uint_to_fp>; > - > -def VCVTf2sq : N2VQ<0b11, 0b11, 0b10, 0b11, 0b01110, 0, "vcvt", "s32.f32", > - v4i32, v4f32, fp_to_sint>; > -def VCVTf2uq : N2VQ<0b11, 0b11, 0b10, 0b11, 0b01111, 0, "vcvt", "u32.f32", > - v4i32, v4f32, fp_to_uint>; > -def VCVTs2fq : N2VQ<0b11, 0b11, 0b10, 0b11, 0b01100, 0, "vcvt", "f32.s32", > - v4f32, v4i32, sint_to_fp>; > -def VCVTu2fq : N2VQ<0b11, 0b11, 0b10, 0b11, 0b01101, 0, "vcvt", "f32.u32", > - v4f32, v4i32, uint_to_fp>; > +def VCVTf2sd : N2VDX<0b11, 0b11, 0b10, 0b11, 0b01110, 0, "vcvt", "s32.f32", > + v2i32, v2f32, fp_to_sint>; > +def VCVTf2ud : N2VDX<0b11, 0b11, 0b10, 0b11, 0b01111, 0, "vcvt", "u32.f32", > + v2i32, v2f32, fp_to_uint>; > +def VCVTs2fd : N2VDX<0b11, 0b11, 0b10, 0b11, 0b01100, 0, "vcvt", "f32.s32", > + v2f32, v2i32, sint_to_fp>; > +def VCVTu2fd : N2VDX<0b11, 0b11, 0b10, 0b11, 0b01101, 0, "vcvt", "f32.u32", > + v2f32, v2i32, uint_to_fp>; > + > +def VCVTf2sq : N2VQX<0b11, 0b11, 0b10, 0b11, 0b01110, 0, "vcvt", "s32.f32", > + v4i32, v4f32, fp_to_sint>; > +def VCVTf2uq : N2VQX<0b11, 0b11, 0b10, 0b11, 0b01111, 0, "vcvt", "u32.f32", > + v4i32, v4f32, fp_to_uint>; > +def VCVTs2fq : N2VQX<0b11, 0b11, 0b10, 0b11, 0b01100, 0, "vcvt", "f32.s32", > + v4f32, v4i32, sint_to_fp>; > +def VCVTu2fq : N2VQX<0b11, 0b11, 0b10, 0b11, 0b01101, 0, "vcvt", "f32.u32", > + v4f32, v4i32, uint_to_fp>; > > // VCVT : Vector Convert Between Floating-Point and Fixed-Point. > def VCVTf2xsd : N2VCvtD<0, 1, 0b1111, 0, 1, "vcvt", "s32.f32", > @@ -2945,6 +3263,8 @@ > > // VEXT : Vector Extract > > +let NSF = NVdVnVmImmVectorExtractFrm, > + NSForm = NVdVnVmImmVectorExtractFrm.Value in { > class VEXTd > : N3V<0,1,0b11,{?,?,?,?},0,0, (outs DPR:$dst), > (ins DPR:$lhs, DPR:$rhs, i32imm:$index), IIC_VEXTD, > @@ -2958,6 +3278,7 @@ > OpcodeStr, Dt, "$dst, $lhs, $rhs, $index", "", > [(set QPR:$dst, (Ty (NEONvext (Ty QPR:$lhs), > (Ty QPR:$rhs), imm:$index)))]>; > +} > > def VEXTd8 : VEXTd<"vext", "8", v8i8>; > def VEXTd16 : VEXTd<"vext", "16", v4i16>; > @@ -3001,6 +3322,8 @@ > > // Vector Table Lookup and Table Extension. > > +let NSF = VTBLFrm, NSForm = VTBLFrm.Value in { > + > // VTBL : Vector Table Lookup > def VTBL1 > : N3V<1,1,0b11,0b1000,0,0, (outs DPR:$dst), > @@ -3057,6 +3380,8 @@ > DPR:$tbl2, DPR:$tbl3, DPR:$tbl4, DPR:$src)))]>; > } // hasExtraSrcRegAllocReq = 1 > > +} // End of "let NSF = VTBLFrm, ..." > + > //===----------------------------------------------------------------------===// > // NEON instructions for single-precision FP math > //===----------------------------------------------------------------------===// > > Modified: llvm/trunk/lib/Target/ARM/AsmPrinter/ARMAsmPrinter.cpp > URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Target/ARM/AsmPrinter/ARMAsmPrinter.cpp?rev=98745&r1=98744&r2=98745&view=diff > ============================================================================== > --- llvm/trunk/lib/Target/ARM/AsmPrinter/ARMAsmPrinter.cpp (original) > +++ llvm/trunk/lib/Target/ARM/AsmPrinter/ARMAsmPrinter.cpp Wed Mar 17 12:52:21 2010 > @@ -120,7 +120,7 @@ > void printT2AddrModeImm8Operand(const MachineInstr *MI, int OpNum); > void printT2AddrModeImm8s4Operand(const MachineInstr *MI, int OpNum); > void printT2AddrModeImm8OffsetOperand(const MachineInstr *MI, int OpNum); > - void printT2AddrModeImm8s4OffsetOperand(const MachineInstr *MI, int OpNum) {} > + void printT2AddrModeImm8s4OffsetOperand(const MachineInstr *MI, int OpNum); > void printT2AddrModeSoRegOperand(const MachineInstr *MI, int OpNum); > > void printCPSOptionOperand(const MachineInstr *MI, int OpNum) {} > @@ -431,16 +431,16 @@ > O << "[" << getRegisterName(MO1.getReg()); > > if (!MO2.getReg()) { > - if (ARM_AM::getAM2Offset(MO3.getImm())) // Don't print +0. > + if (ARM_AM::getAM2Offset(MO3.getImm())) // Don't print +0. > O << ", #" > - << (char)ARM_AM::getAM2Op(MO3.getImm()) > + << ARM_AM::getAddrOpcStr(ARM_AM::getAM2Op(MO3.getImm())) > << ARM_AM::getAM2Offset(MO3.getImm()); > O << "]"; > return; > } > > O << ", " > - << (char)ARM_AM::getAM2Op(MO3.getImm()) > + << ARM_AM::getAddrOpcStr(ARM_AM::getAM2Op(MO3.getImm())) > << getRegisterName(MO2.getReg()); > > if (unsigned ShImm = ARM_AM::getAM2Offset(MO3.getImm())) > @@ -458,12 +458,12 @@ > unsigned ImmOffs = ARM_AM::getAM2Offset(MO2.getImm()); > assert(ImmOffs && "Malformed indexed load / store!"); > O << "#" > - << (char)ARM_AM::getAM2Op(MO2.getImm()) > + << ARM_AM::getAddrOpcStr(ARM_AM::getAM2Op(MO2.getImm())) > << ImmOffs; > return; > } > > - O << (char)ARM_AM::getAM2Op(MO2.getImm()) > + O << ARM_AM::getAddrOpcStr(ARM_AM::getAM2Op(MO2.getImm())) > << getRegisterName(MO1.getReg()); > > if (unsigned ShImm = ARM_AM::getAM2Offset(MO2.getImm())) > @@ -490,7 +490,7 @@ > > if (unsigned ImmOffs = ARM_AM::getAM3Offset(MO3.getImm())) > O << ", #" > - << (char)ARM_AM::getAM3Op(MO3.getImm()) > + << ARM_AM::getAddrOpcStr(ARM_AM::getAM3Op(MO3.getImm())) > << ImmOffs; > O << "]"; > } > @@ -508,7 +508,7 @@ > unsigned ImmOffs = ARM_AM::getAM3Offset(MO2.getImm()); > assert(ImmOffs && "Malformed indexed load / store!"); > O << "#" > - << (char)ARM_AM::getAM3Op(MO2.getImm()) > + << ARM_AM::getAddrOpcStr(ARM_AM::getAM3Op(MO2.getImm())) > << ImmOffs; > } > > @@ -553,7 +553,7 @@ > > if (unsigned ImmOffs = ARM_AM::getAM5Offset(MO2.getImm())) { > O << ", #" > - << (char)ARM_AM::getAM5Op(MO2.getImm()) > + << ARM_AM::getAddrOpcStr(ARM_AM::getAM5Op(MO2.getImm())) > << ImmOffs*4; > } > O << "]"; > @@ -589,7 +589,7 @@ > > const MachineOperand &MO1 = MI->getOperand(Op); > assert(TargetRegisterInfo::isPhysicalRegister(MO1.getReg())); > - O << "[pc, +" << getRegisterName(MO1.getReg()) << "]"; > + O << "[pc, " << getRegisterName(MO1.getReg()) << "]"; > } > > void > @@ -612,10 +612,11 @@ > ARMAsmPrinter::printThumbITMask(const MachineInstr *MI, int Op) { > // (3 - the number of trailing zeros) is the number of then / else. > unsigned Mask = MI->getOperand(Op).getImm(); > + unsigned CondBit0 = Mask >> 4 & 1; > unsigned NumTZ = CountTrailingZeros_32(Mask); > assert(NumTZ <= 3 && "Invalid IT mask!"); > for (unsigned Pos = 3, e = NumTZ; Pos > e; --Pos) { > - bool T = (Mask & (1 << Pos)) == 0; > + bool T = ((Mask >> Pos) & 1) == CondBit0; > if (T) > O << 't'; > else > @@ -647,7 +648,7 @@ > if (MO3.getReg()) > O << ", " << getRegisterName(MO3.getReg()); > else if (unsigned ImmOffs = MO2.getImm()) > - O << ", #+" << ImmOffs * Scale; > + O << ", #" << ImmOffs * Scale; > O << "]"; > } > > @@ -669,7 +670,7 @@ > const MachineOperand &MO2 = MI->getOperand(Op+1); > O << "[" << getRegisterName(MO1.getReg()); > if (unsigned ImmOffs = MO2.getImm()) > - O << ", #+" << ImmOffs*4; > + O << ", #" << ImmOffs*4; > O << "]"; > } > > @@ -705,7 +706,7 @@ > > unsigned OffImm = MO2.getImm(); > if (OffImm) // Don't print +0. > - O << ", #+" << OffImm; > + O << ", #" << OffImm; > O << "]"; > } > > @@ -721,7 +722,7 @@ > if (OffImm < 0) > O << ", #-" << -OffImm; > else if (OffImm > 0) > - O << ", #+" << OffImm; > + O << ", #" << OffImm; > O << "]"; > } > > @@ -737,7 +738,7 @@ > if (OffImm < 0) > O << ", #-" << -OffImm * 4; > else if (OffImm > 0) > - O << ", #+" << OffImm * 4; > + O << ", #" << OffImm * 4; > O << "]"; > } > > @@ -749,7 +750,18 @@ > if (OffImm < 0) > O << "#-" << -OffImm; > else if (OffImm > 0) > - O << "#+" << OffImm; > + O << "#" << OffImm; > +} > + > +void ARMAsmPrinter::printT2AddrModeImm8s4OffsetOperand(const MachineInstr *MI, > + int OpNum) { > + const MachineOperand &MO1 = MI->getOperand(OpNum); > + int32_t OffImm = (int32_t)MO1.getImm() / 4; > + // Don't print +0. > + if (OffImm < 0) > + O << "#-" << -OffImm * 4; > + else if (OffImm > 0) > + O << "#" << OffImm * 4; > } > > void ARMAsmPrinter::printT2AddrModeSoRegOperand(const MachineInstr *MI, > > Modified: llvm/trunk/lib/Target/ARM/AsmPrinter/ARMInstPrinter.cpp > URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Target/ARM/AsmPrinter/ARMInstPrinter.cpp?rev=98745&r1=98744&r2=98745&view=diff > ============================================================================== > --- llvm/trunk/lib/Target/ARM/AsmPrinter/ARMInstPrinter.cpp (original) > +++ llvm/trunk/lib/Target/ARM/AsmPrinter/ARMInstPrinter.cpp Wed Mar 17 12:52:21 2010 > @@ -28,7 +28,159 @@ > #undef MachineInstr > #undef ARMAsmPrinter > > -void ARMInstPrinter::printInst(const MCInst *MI) { printInstruction(MI); } > +static unsigned NextReg(unsigned Reg) { > + switch (Reg) { > + case ARM::D0: > + return ARM::D1; > + case ARM::D1: > + return ARM::D2; > + case ARM::D2: > + return ARM::D3; > + case ARM::D3: > + return ARM::D4; > + case ARM::D4: > + return ARM::D5; > + case ARM::D5: > + return ARM::D6; > + case ARM::D6: > + return ARM::D7; > + case ARM::D7: > + return ARM::D8; > + case ARM::D8: > + return ARM::D9; > + case ARM::D9: > + return ARM::D10; > + case ARM::D10: > + return ARM::D11; > + case ARM::D11: > + return ARM::D12; > + case ARM::D12: > + return ARM::D13; > + case ARM::D13: > + return ARM::D14; > + case ARM::D14: > + return ARM::D15; > + case ARM::D15: > + return ARM::D16; > + case ARM::D16: > + return ARM::D17; > + case ARM::D17: > + return ARM::D18; > + case ARM::D18: > + return ARM::D19; > + case ARM::D19: > + return ARM::D20; > + case ARM::D20: > + return ARM::D21; > + case ARM::D21: > + return ARM::D22; > + case ARM::D22: > + return ARM::D23; > + case ARM::D23: > + return ARM::D24; > + case ARM::D24: > + return ARM::D25; > + case ARM::D25: > + return ARM::D26; > + case ARM::D26: > + return ARM::D27; > + case ARM::D27: > + return ARM::D28; > + case ARM::D28: > + return ARM::D29; > + case ARM::D29: > + return ARM::D30; > + case ARM::D30: > + return ARM::D31; > + > + default: > + assert(0 && "Unexpected register enum"); > + } > +} > + > +void ARMInstPrinter::printInst(const MCInst *MI) { > + // Check for MOVs and print canonical forms, instead. > + if (MI->getOpcode() == ARM::MOVs) { > + const MCOperand &Dst = MI->getOperand(0); > + const MCOperand &MO1 = MI->getOperand(1); > + const MCOperand &MO2 = MI->getOperand(2); > + const MCOperand &MO3 = MI->getOperand(3); > + > + O << '\t' << ARM_AM::getShiftOpcStr(ARM_AM::getSORegShOp(MO3.getImm())); > + printSBitModifierOperand(MI, 6); > + printPredicateOperand(MI, 4); > + > + O << '\t' << getRegisterName(Dst.getReg()) > + << ", " << getRegisterName(MO1.getReg()); > + > + if (ARM_AM::getSORegShOp(MO3.getImm()) == ARM_AM::rrx) > + return; > + > + O << ", "; > + > + if (MO2.getReg()) { > + O << getRegisterName(MO2.getReg()); > + assert(ARM_AM::getSORegOffset(MO3.getImm()) == 0); > + } else { > + O << "#" << ARM_AM::getSORegOffset(MO3.getImm()); > + } > + return; > + } > + > + // A8.6.123 PUSH > + if ((MI->getOpcode() == ARM::STM_UPD || MI->getOpcode() == ARM::t2STM_UPD) && > + MI->getOperand(0).getReg() == ARM::SP) { > + const MCOperand &MO1 = MI->getOperand(2); > + if (ARM_AM::getAM4SubMode(MO1.getImm()) == ARM_AM::db) { > + O << '\t' << "push"; > + printPredicateOperand(MI, 3); > + O << '\t'; > + printRegisterList(MI, 5); > + return; > + } > + } > + > + // A8.6.122 POP > + if ((MI->getOpcode() == ARM::LDM_UPD || MI->getOpcode() == ARM::t2LDM_UPD) && > + MI->getOperand(0).getReg() == ARM::SP) { > + const MCOperand &MO1 = MI->getOperand(2); > + if (ARM_AM::getAM4SubMode(MO1.getImm()) == ARM_AM::ia) { > + O << '\t' << "pop"; > + printPredicateOperand(MI, 3); > + O << '\t'; > + printRegisterList(MI, 5); > + return; > + } > + } > + > + // A8.6.355 VPUSH > + if ((MI->getOpcode() == ARM::VSTMS_UPD || MI->getOpcode() ==ARM::VSTMD_UPD) && > + MI->getOperand(0).getReg() == ARM::SP) { > + const MCOperand &MO1 = MI->getOperand(2); > + if (ARM_AM::getAM5SubMode(MO1.getImm()) == ARM_AM::db) { > + O << '\t' << "vpush"; > + printPredicateOperand(MI, 3); > + O << '\t'; > + printRegisterList(MI, 5); > + return; > + } > + } > + > + // A8.6.354 VPOP > + if ((MI->getOpcode() == ARM::VLDMS_UPD || MI->getOpcode() ==ARM::VLDMD_UPD) && > + MI->getOperand(0).getReg() == ARM::SP) { > + const MCOperand &MO1 = MI->getOperand(2); > + if (ARM_AM::getAM5SubMode(MO1.getImm()) == ARM_AM::ia) { > + O << '\t' << "vpop"; > + printPredicateOperand(MI, 3); > + O << '\t'; > + printRegisterList(MI, 5); > + return; > + } > + } > + > + printInstruction(MI); > + } > > void ARMInstPrinter::printOperand(const MCInst *MI, unsigned OpNo, > const char *Modifier) { > @@ -36,6 +188,9 @@ > if (Op.isReg()) { > unsigned Reg = Op.getReg(); > if (Modifier && strcmp(Modifier, "dregpair") == 0) { > + O << '{' << getRegisterName(Reg) << ", " > + << getRegisterName(NextReg(Reg)) << '}'; > +#if 0 > // FIXME: Breaks e.g. ARM/vmul.ll. > assert(0); > /* > @@ -44,6 +199,7 @@ > O << '{' > << getRegisterName(DRegLo) << ',' << getRegisterName(DRegHi) > << '}';*/ > +#endif > } else if (Modifier && strcmp(Modifier, "lane") == 0) { > assert(0); > /* > @@ -56,7 +212,9 @@ > O << getRegisterName(Reg); > } > } else if (Op.isImm()) { > - assert((Modifier == 0 || Modifier[0] == 0) && "No modifiers supported"); > + bool isCallOp = Modifier && !strcmp(Modifier, "call"); > + assert(isCallOp || > + ((Modifier == 0 || Modifier[0] == 0) && "No modifiers supported")); > O << '#' << Op.getImm(); > } else { > assert((Modifier == 0 || Modifier[0] == 0) && "No modifiers supported"); > @@ -142,17 +300,17 @@ > O << "[" << getRegisterName(MO1.getReg()); > > if (!MO2.getReg()) { > - if (ARM_AM::getAM2Offset(MO3.getImm())) // Don't print +0. > + if (ARM_AM::getAM2Offset(MO3.getImm())) // Don't print +0. > O << ", #" > - << (char)ARM_AM::getAM2Op(MO3.getImm()) > - << ARM_AM::getAM2Offset(MO3.getImm()); > + << ARM_AM::getAddrOpcStr(ARM_AM::getAM2Op(MO3.getImm())) > + << ARM_AM::getAM2Offset(MO3.getImm()); > O << "]"; > return; > } > > O << ", " > - << (char)ARM_AM::getAM2Op(MO3.getImm()) > - << getRegisterName(MO2.getReg()); > + << ARM_AM::getAddrOpcStr(ARM_AM::getAM2Op(MO3.getImm())) > + << getRegisterName(MO2.getReg()); > > if (unsigned ShImm = ARM_AM::getAM2Offset(MO3.getImm())) > O << ", " > @@ -169,11 +327,14 @@ > if (!MO1.getReg()) { > unsigned ImmOffs = ARM_AM::getAM2Offset(MO2.getImm()); > assert(ImmOffs && "Malformed indexed load / store!"); > - O << '#' << (char)ARM_AM::getAM2Op(MO2.getImm()) << ImmOffs; > + O << '#' > + << ARM_AM::getAddrOpcStr(ARM_AM::getAM2Op(MO2.getImm())) > + << ImmOffs; > return; > } > > - O << (char)ARM_AM::getAM2Op(MO2.getImm()) << getRegisterName(MO1.getReg()); > + O << ARM_AM::getAddrOpcStr(ARM_AM::getAM2Op(MO2.getImm())) > + << getRegisterName(MO1.getReg()); > > if (unsigned ShImm = ARM_AM::getAM2Offset(MO2.getImm())) > O << ", " > @@ -196,8 +357,8 @@ > > if (unsigned ImmOffs = ARM_AM::getAM3Offset(MO3.getImm())) > O << ", #" > - << (char)ARM_AM::getAM3Op(MO3.getImm()) > - << ImmOffs; > + << ARM_AM::getAddrOpcStr(ARM_AM::getAM3Op(MO3.getImm())) > + << ImmOffs; > O << ']'; > } > > @@ -214,9 +375,9 @@ > > unsigned ImmOffs = ARM_AM::getAM3Offset(MO2.getImm()); > assert(ImmOffs && "Malformed indexed load / store!"); > - O << "#" > - << (char)ARM_AM::getAM3Op(MO2.getImm()) > - << ImmOffs; > + O << '#' > + << ARM_AM::getAddrOpcStr(ARM_AM::getAM3Op(MO2.getImm())) > + << ImmOffs; > } > > > @@ -259,7 +420,7 @@ > > if (unsigned ImmOffs = ARM_AM::getAM5Offset(MO2.getImm())) { > O << ", #" > - << (char)ARM_AM::getAM5Op(MO2.getImm()) > + << ARM_AM::getAddrOpcStr(ARM_AM::getAM5Op(MO2.getImm())) > << ImmOffs*4; > } > O << "]"; > @@ -298,14 +459,56 @@ > > void ARMInstPrinter::printRegisterList(const MCInst *MI, unsigned OpNum) { > O << "{"; > - // Always skip the first operand, it's the optional (and implicit writeback). > - for (unsigned i = OpNum+1, e = MI->getNumOperands(); i != e; ++i) { > - if (i != OpNum+1) O << ", "; > + for (unsigned i = OpNum, e = MI->getNumOperands(); i != e; ++i) { > + if (i != OpNum) O << ", "; > O << getRegisterName(MI->getOperand(i).getReg()); > } > O << "}"; > } > > +void ARMInstPrinter::printCPSOptionOperand(const MCInst *MI, unsigned OpNum) { > + const MCOperand &Op = MI->getOperand(OpNum); > + unsigned option = Op.getImm(); > + unsigned mode = option & 31; > + bool changemode = option >> 5 & 1; > + unsigned AIF = option >> 6 & 7; > + unsigned imod = option >> 9 & 3; > + if (imod == 2) > + O << "ie"; > + else if (imod == 3) > + O << "id"; > + O << '\t'; > + if (imod > 1) { > + if (AIF & 4) O << 'a'; > + if (AIF & 2) O << 'i'; > + if (AIF & 1) O << 'f'; > + if (AIF > 0 && changemode) O << ", "; > + } > + if (changemode) > + O << '#' << mode; > +} > + > +void ARMInstPrinter::printMSRMaskOperand(const MCInst *MI, unsigned OpNum) { > + const MCOperand &Op = MI->getOperand(OpNum); > + unsigned Mask = Op.getImm(); > + if (Mask) { > + O << '_'; > + if (Mask & 8) O << 'f'; > + if (Mask & 4) O << 's'; > + if (Mask & 2) O << 'x'; > + if (Mask & 1) O << 'c'; > + } > +} > + > +void ARMInstPrinter::printNegZeroOperand(const MCInst *MI, unsigned OpNum){ > + const MCOperand &Op = MI->getOperand(OpNum); > + O << '#'; > + if (Op.getImm() < 0) > + O << '-' << (-Op.getImm() - 1); > + else > + O << Op.getImm(); > +} > + > void ARMInstPrinter::printPredicateOperand(const MCInst *MI, unsigned OpNum) { > ARMCC::CondCodes CC = (ARMCC::CondCodes)MI->getOperand(OpNum).getImm(); > if (CC != ARMCC::AL) > @@ -347,3 +550,191 @@ > void ARMInstPrinter::printThumbS4ImmOperand(const MCInst *MI, unsigned OpNum) { > O << "#" << MI->getOperand(OpNum).getImm() * 4; > } > + > +void ARMInstPrinter::printThumbITMask(const MCInst *MI, unsigned OpNum) { > + // (3 - the number of trailing zeros) is the number of then / else. > + unsigned Mask = MI->getOperand(OpNum).getImm(); > + unsigned CondBit0 = Mask >> 4 & 1; > + unsigned NumTZ = CountTrailingZeros_32(Mask); > + assert(NumTZ <= 3 && "Invalid IT mask!"); > + for (unsigned Pos = 3, e = NumTZ; Pos > e; --Pos) { > + bool T = ((Mask >> Pos) & 1) == CondBit0; > + if (T) > + O << 't'; > + else > + O << 'e'; > + } > +} > + > +void ARMInstPrinter::printThumbAddrModeRROperand(const MCInst *MI, unsigned Op) > +{ > + const MCOperand &MO1 = MI->getOperand(Op); > + const MCOperand &MO2 = MI->getOperand(Op+1); > + O << "[" << getRegisterName(MO1.getReg()); > + O << ", " << getRegisterName(MO2.getReg()) << "]"; > +} > + > +void ARMInstPrinter::printThumbAddrModeRI5Operand(const MCInst *MI, unsigned Op, > + unsigned Scale) { > + const MCOperand &MO1 = MI->getOperand(Op); > + const MCOperand &MO2 = MI->getOperand(Op+1); > + const MCOperand &MO3 = MI->getOperand(Op+2); > + > + if (!MO1.isReg()) { // FIXME: This is for CP entries, but isn't right. > + printOperand(MI, Op); > + return; > + } > + > + O << "[" << getRegisterName(MO1.getReg()); > + if (MO3.getReg()) > + O << ", " << getRegisterName(MO3.getReg()); > + else if (unsigned ImmOffs = MO2.getImm()) > + O << ", #" << ImmOffs * Scale; > + O << "]"; > +} > + > +void ARMInstPrinter::printThumbAddrModeS1Operand(const MCInst *MI, unsigned Op) > +{ > + printThumbAddrModeRI5Operand(MI, Op, 1); > +} > + > +void ARMInstPrinter::printThumbAddrModeS2Operand(const MCInst *MI, unsigned Op) > +{ > + printThumbAddrModeRI5Operand(MI, Op, 2); > +} > + > +void ARMInstPrinter::printThumbAddrModeS4Operand(const MCInst *MI, unsigned Op) > +{ > + printThumbAddrModeRI5Operand(MI, Op, 4); > +} > + > +void ARMInstPrinter::printThumbAddrModeSPOperand(const MCInst *MI,unsigned Op) { > + const MCOperand &MO1 = MI->getOperand(Op); > + const MCOperand &MO2 = MI->getOperand(Op+1); > + O << "[" << getRegisterName(MO1.getReg()); > + if (unsigned ImmOffs = MO2.getImm()) > + O << ", #" << ImmOffs*4; > + O << "]"; > +} > + > +void ARMInstPrinter::printTBAddrMode(const MCInst *MI, unsigned OpNum) { > + O << "[pc, " << getRegisterName(MI->getOperand(OpNum).getReg()); > + if (MI->getOpcode() == ARM::t2TBH) > + O << ", lsl #1"; > + O << ']'; > +} > + > +// Constant shifts t2_so_reg is a 2-operand unit corresponding to the Thumb2 > +// register with shift forms. > +// REG 0 0 - e.g. R5 > +// REG IMM, SH_OPC - e.g. R5, LSL #3 > +void ARMInstPrinter::printT2SOOperand(const MCInst *MI, unsigned OpNum) { > + const MCOperand &MO1 = MI->getOperand(OpNum); > + const MCOperand &MO2 = MI->getOperand(OpNum+1); > + > + unsigned Reg = MO1.getReg(); > + O << getRegisterName(Reg); > + > + // Print the shift opc. > + O << ", " > + << ARM_AM::getShiftOpcStr(ARM_AM::getSORegShOp(MO2.getImm())) > + << " "; > + > + assert(MO2.isImm() && "Not a valid t2_so_reg value!"); > + O << "#" << ARM_AM::getSORegOffset(MO2.getImm()); > +} > + > +void ARMInstPrinter::printT2AddrModeImm12Operand(const MCInst *MI, > + unsigned OpNum) { > + const MCOperand &MO1 = MI->getOperand(OpNum); > + const MCOperand &MO2 = MI->getOperand(OpNum+1); > + > + O << "[" << getRegisterName(MO1.getReg()); > + > + unsigned OffImm = MO2.getImm(); > + if (OffImm) // Don't print +0. > + O << ", #" << OffImm; > + O << "]"; > +} > + > +void ARMInstPrinter::printT2AddrModeImm8Operand(const MCInst *MI, > + unsigned OpNum) { > + const MCOperand &MO1 = MI->getOperand(OpNum); > + const MCOperand &MO2 = MI->getOperand(OpNum+1); > + > + O << "[" << getRegisterName(MO1.getReg()); > + > + int32_t OffImm = (int32_t)MO2.getImm(); > + // Don't print +0. > + if (OffImm < 0) > + O << ", #-" << -OffImm; > + else if (OffImm > 0) > + O << ", #" << OffImm; > + O << "]"; > +} > + > +void ARMInstPrinter::printT2AddrModeImm8s4Operand(const MCInst *MI, > + unsigned OpNum) { > + const MCOperand &MO1 = MI->getOperand(OpNum); > + const MCOperand &MO2 = MI->getOperand(OpNum+1); > + > + O << "[" << getRegisterName(MO1.getReg()); > + > + int32_t OffImm = (int32_t)MO2.getImm() / 4; > + // Don't print +0. > + if (OffImm < 0) > + O << ", #-" << -OffImm * 4; > + else if (OffImm > 0) > + O << ", #" << OffImm * 4; > + O << "]"; > +} > + > +void ARMInstPrinter::printT2AddrModeImm8OffsetOperand(const MCInst *MI, > + unsigned OpNum) { > + const MCOperand &MO1 = MI->getOperand(OpNum); > + int32_t OffImm = (int32_t)MO1.getImm(); > + // Don't print +0. > + if (OffImm < 0) > + O << "#-" << -OffImm; > + else if (OffImm > 0) > + O << "#" << OffImm; > +} > + > +void ARMInstPrinter::printT2AddrModeImm8s4OffsetOperand(const MCInst *MI, > + unsigned OpNum) { > + const MCOperand &MO1 = MI->getOperand(OpNum); > + int32_t OffImm = (int32_t)MO1.getImm() / 4; > + // Don't print +0. > + if (OffImm < 0) > + O << "#-" << -OffImm * 4; > + else if (OffImm > 0) > + O << "#" << OffImm * 4; > +} > + > +void ARMInstPrinter::printT2AddrModeSoRegOperand(const MCInst *MI, > + unsigned OpNum) { > + const MCOperand &MO1 = MI->getOperand(OpNum); > + const MCOperand &MO2 = MI->getOperand(OpNum+1); > + const MCOperand &MO3 = MI->getOperand(OpNum+2); > + > + O << "[" << getRegisterName(MO1.getReg()); > + > + assert(MO2.getReg() && "Invalid so_reg load / store address!"); > + O << ", " << getRegisterName(MO2.getReg()); > + > + unsigned ShAmt = MO3.getImm(); > + if (ShAmt) { > + assert(ShAmt <= 3 && "Not a valid Thumb2 addressing mode!"); > + O << ", lsl #" << ShAmt; > + } > + O << "]"; > +} > + > +void ARMInstPrinter::printVFPf32ImmOperand(const MCInst *MI, unsigned OpNum) { > + O << '#' << MI->getOperand(OpNum).getImm(); > +} > + > +void ARMInstPrinter::printVFPf64ImmOperand(const MCInst *MI, unsigned OpNum) { > + O << '#' << MI->getOperand(OpNum).getImm(); > +} > + > > Modified: llvm/trunk/lib/Target/ARM/AsmPrinter/ARMInstPrinter.h > URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Target/ARM/AsmPrinter/ARMInstPrinter.h?rev=98745&r1=98744&r2=98745&view=diff > ============================================================================== > --- llvm/trunk/lib/Target/ARM/AsmPrinter/ARMInstPrinter.h (original) > +++ llvm/trunk/lib/Target/ARM/AsmPrinter/ARMInstPrinter.h Wed Mar 17 12:52:21 2010 > @@ -54,26 +54,26 @@ > void printBitfieldInvMaskImmOperand(const MCInst *MI, unsigned OpNum); > > void printThumbS4ImmOperand(const MCInst *MI, unsigned OpNum); > - void printThumbITMask(const MCInst *MI, unsigned OpNum) {} > - void printThumbAddrModeRROperand(const MCInst *MI, unsigned OpNum) {} > + void printThumbITMask(const MCInst *MI, unsigned OpNum); > + void printThumbAddrModeRROperand(const MCInst *MI, unsigned OpNum); > void printThumbAddrModeRI5Operand(const MCInst *MI, unsigned OpNum, > - unsigned Scale) {} > - void printThumbAddrModeS1Operand(const MCInst *MI, unsigned OpNum) {} > - void printThumbAddrModeS2Operand(const MCInst *MI, unsigned OpNum) {} > - void printThumbAddrModeS4Operand(const MCInst *MI, unsigned OpNum) {} > - void printThumbAddrModeSPOperand(const MCInst *MI, unsigned OpNum) {} > + unsigned Scale); > + void printThumbAddrModeS1Operand(const MCInst *MI, unsigned OpNum); > + void printThumbAddrModeS2Operand(const MCInst *MI, unsigned OpNum); > + void printThumbAddrModeS4Operand(const MCInst *MI, unsigned OpNum); > + void printThumbAddrModeSPOperand(const MCInst *MI, unsigned OpNum); > > - void printT2SOOperand(const MCInst *MI, unsigned OpNum) {} > - void printT2AddrModeImm12Operand(const MCInst *MI, unsigned OpNum) {} > - void printT2AddrModeImm8Operand(const MCInst *MI, unsigned OpNum) {} > - void printT2AddrModeImm8s4Operand(const MCInst *MI, unsigned OpNum) {} > - void printT2AddrModeImm8OffsetOperand(const MCInst *MI, unsigned OpNum) {} > - void printT2AddrModeImm8s4OffsetOperand(const MCInst *MI, unsigned OpNum) {} > - void printT2AddrModeSoRegOperand(const MCInst *MI, unsigned OpNum) {} > + void printT2SOOperand(const MCInst *MI, unsigned OpNum); > + void printT2AddrModeImm12Operand(const MCInst *MI, unsigned OpNum); > + void printT2AddrModeImm8Operand(const MCInst *MI, unsigned OpNum); > + void printT2AddrModeImm8s4Operand(const MCInst *MI, unsigned OpNum); > + void printT2AddrModeImm8OffsetOperand(const MCInst *MI, unsigned OpNum); > + void printT2AddrModeImm8s4OffsetOperand(const MCInst *MI, unsigned OpNum); > + void printT2AddrModeSoRegOperand(const MCInst *MI, unsigned OpNum); > > - void printCPSOptionOperand(const MCInst *MI, unsigned OpNum) {} > - void printMSRMaskOperand(const MCInst *MI, unsigned OpNum) {} > - void printNegZeroOperand(const MCInst *MI, unsigned OpNum) {} > + void printCPSOptionOperand(const MCInst *MI, unsigned OpNum); > + void printMSRMaskOperand(const MCInst *MI, unsigned OpNum); > + void printNegZeroOperand(const MCInst *MI, unsigned OpNum); > void printPredicateOperand(const MCInst *MI, unsigned OpNum); > void printMandatoryPredicateOperand(const MCInst *MI, unsigned OpNum); > void printSBitModifierOperand(const MCInst *MI, unsigned OpNum); > @@ -82,10 +82,10 @@ > const char *Modifier); > void printJTBlockOperand(const MCInst *MI, unsigned OpNum) {} > void printJT2BlockOperand(const MCInst *MI, unsigned OpNum) {} > - void printTBAddrMode(const MCInst *MI, unsigned OpNum) {} > + void printTBAddrMode(const MCInst *MI, unsigned OpNum); > void printNoHashImmediate(const MCInst *MI, unsigned OpNum); > - void printVFPf32ImmOperand(const MCInst *MI, int OpNum) {} > - void printVFPf64ImmOperand(const MCInst *MI, int OpNum) {} > + void printVFPf32ImmOperand(const MCInst *MI, unsigned OpNum); > + void printVFPf64ImmOperand(const MCInst *MI, unsigned OpNum); > void printHex8ImmOperand(const MCInst *MI, int OpNum) {} > void printHex16ImmOperand(const MCInst *MI, int OpNum) {} > void printHex32ImmOperand(const MCInst *MI, int OpNum) {} > > Modified: llvm/trunk/test/CodeGen/ARM/2009-10-27-double-align.ll > URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/CodeGen/ARM/2009-10-27-double-align.ll?rev=98745&r1=98744&r2=98745&view=diff > ============================================================================== > --- llvm/trunk/test/CodeGen/ARM/2009-10-27-double-align.ll (original) > +++ llvm/trunk/test/CodeGen/ARM/2009-10-27-double-align.ll Wed Mar 17 12:52:21 2010 > @@ -4,8 +4,8 @@ > > define arm_aapcscc void @g() { > entry: > -;CHECK: [sp, #+8] > -;CHECK: [sp, #+12] > +;CHECK: [sp, #8] > +;CHECK: [sp, #12] > ;CHECK: [sp] > tail call arm_aapcscc void (i8*, ...)* @f(i8* getelementptr ([1 x i8]* @.str, i32 0, i32 0), i32 1, double 2.000000e+00, i32 3, double 4.000000e+00) > ret void > > Modified: llvm/trunk/test/CodeGen/ARM/2009-10-30.ll > URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/CodeGen/ARM/2009-10-30.ll?rev=98745&r1=98744&r2=98745&view=diff > ============================================================================== > --- llvm/trunk/test/CodeGen/ARM/2009-10-30.ll (original) > +++ llvm/trunk/test/CodeGen/ARM/2009-10-30.ll Wed Mar 17 12:52:21 2010 > @@ -6,7 +6,7 @@ > entry: > ;CHECK: sub sp, sp, #4 > ;CHECK: add r{{[0-9]+}}, sp, #8 > -;CHECK: str r{{[0-9]+}}, [sp], #+4 > +;CHECK: str r{{[0-9]+}}, [sp], #4 > ;CHECK: bx lr > %ap = alloca i8*, align 4 > %ap1 = bitcast i8** %ap to i8* > > Modified: llvm/trunk/test/CodeGen/ARM/arm-negative-stride.ll > URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/CodeGen/ARM/arm-negative-stride.ll?rev=98745&r1=98744&r2=98745&view=diff > ============================================================================== > --- llvm/trunk/test/CodeGen/ARM/arm-negative-stride.ll (original) > +++ llvm/trunk/test/CodeGen/ARM/arm-negative-stride.ll Wed Mar 17 12:52:21 2010 > @@ -5,7 +5,7 @@ > > define void @test(i32* %P, i32 %A, i32 %i) nounwind { > entry: > -; CHECK: str r1, [{{r.*}}, +{{r.*}}, lsl #2] > +; CHECK: str r1, [{{r.*}}, {{r.*}}, lsl #2] > icmp eq i32 %i, 0 ; :0 [#uses=1] > br i1 %0, label %return, label %bb > > > Modified: llvm/trunk/test/CodeGen/ARM/globals.ll > URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/CodeGen/ARM/globals.ll?rev=98745&r1=98744&r2=98745&view=diff > ============================================================================== > --- llvm/trunk/test/CodeGen/ARM/globals.ll (original) > +++ llvm/trunk/test/CodeGen/ARM/globals.ll Wed Mar 17 12:52:21 2010 > @@ -41,7 +41,7 @@ > ; DarwinPIC: _test1: > ; DarwinPIC: ldr r0, LCPI1_0 > ; DarwinPIC: LPC1_0: > -; DarwinPIC: ldr r0, [pc, +r0] > +; DarwinPIC: ldr r0, [pc, r0] > ; DarwinPIC: ldr r0, [r0] > ; DarwinPIC: bx lr > > @@ -63,7 +63,7 @@ > > ; LinuxPIC: .LPC1_0: > ; LinuxPIC: add r0, pc, r0 > -; LinuxPIC: ldr r0, [r1, +r0] > +; LinuxPIC: ldr r0, [r1, r0] > ; LinuxPIC: ldr r0, [r0] > ; LinuxPIC: bx lr > > > Modified: llvm/trunk/test/CodeGen/ARM/ldrd.ll > URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/CodeGen/ARM/ldrd.ll?rev=98745&r1=98744&r2=98745&view=diff > ============================================================================== > --- llvm/trunk/test/CodeGen/ARM/ldrd.ll (original) > +++ llvm/trunk/test/CodeGen/ARM/ldrd.ll Wed Mar 17 12:52:21 2010 > @@ -10,10 +10,10 @@ > ;V6: ldrd r2, [r2] > > ;V5: ldr r3, [r2] > -;V5: ldr r2, [r2, #+4] > +;V5: ldr r2, [r2, #4] > > ;EABI: ldr r3, [r2] > -;EABI: ldr r2, [r2, #+4] > +;EABI: ldr r2, [r2, #4] > > %0 = load i64** @b, align 4 > %1 = load i64* %0, align 4 > > Modified: llvm/trunk/test/CodeGen/ARM/str_pre-2.ll > URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/CodeGen/ARM/str_pre-2.ll?rev=98745&r1=98744&r2=98745&view=diff > ============================================================================== > --- llvm/trunk/test/CodeGen/ARM/str_pre-2.ll (original) > +++ llvm/trunk/test/CodeGen/ARM/str_pre-2.ll Wed Mar 17 12:52:21 2010 > @@ -1,5 +1,5 @@ > ; RUN: llc < %s -mtriple=arm-linux-gnu | grep {str.*\\!} > -; RUN: llc < %s -mtriple=arm-linux-gnu | grep {ldr.*\\\[.*\], #+4} > +; RUN: llc < %s -mtriple=arm-linux-gnu | grep {ldr.*\\\[.*\], #4} > > @b = external global i64* > > > Modified: llvm/trunk/test/CodeGen/ARM/tls2.ll > URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/CodeGen/ARM/tls2.ll?rev=98745&r1=98744&r2=98745&view=diff > ============================================================================== > --- llvm/trunk/test/CodeGen/ARM/tls2.ll (original) > +++ llvm/trunk/test/CodeGen/ARM/tls2.ll Wed Mar 17 12:52:21 2010 > @@ -7,7 +7,7 @@ > > define i32 @f() { > ; CHECK-NONPIC: f: > -; CHECK-NONPIC: ldr {{r.}}, [pc, +{{r.}}] > +; CHECK-NONPIC: ldr {{r.}}, [pc, {{r.}}] > ; CHECK-NONPIC: i(gottpoff) > ; CHECK-PIC: f: > ; CHECK-PIC: __tls_get_addr > @@ -18,7 +18,7 @@ > > define i32* @g() { > ; CHECK-NONPIC: g: > -; CHECK-NONPIC: ldr {{r.}}, [pc, +{{r.}}] > +; CHECK-NONPIC: ldr {{r.}}, [pc, {{r.}}] > ; CHECK-NONPIC: i(gottpoff) > ; CHECK-PIC: g: > ; CHECK-PIC: __tls_get_addr > > Modified: llvm/trunk/test/CodeGen/Thumb2/ldr-str-imm12.ll > URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/CodeGen/Thumb2/ldr-str-imm12.ll?rev=98745&r1=98744&r2=98745&view=diff > ============================================================================== > --- llvm/trunk/test/CodeGen/Thumb2/ldr-str-imm12.ll (original) > +++ llvm/trunk/test/CodeGen/Thumb2/ldr-str-imm12.ll Wed Mar 17 12:52:21 2010 > @@ -22,7 +22,7 @@ > > define arm_apcscc %union.rec* @Manifest(%union.rec* %x, %union.rec* %env, %struct.STYLE* %style, %union.rec** %bthr, %union.rec** %fthr, %union.rec** %target, %union.rec** %crs, i32 %ok, i32 %need_expand, %union.rec** %enclose, i32 %fcr) nounwind { > entry: > -; CHECK: ldr.w r9, [r7, #+28] > +; CHECK: ldr.w r9, [r7, #28] > %xgaps.i = alloca [32 x %union.rec*], align 4 ; <[32 x %union.rec*]*> [#uses=0] > %ycomp.i = alloca [32 x %union.rec*], align 4 ; <[32 x %union.rec*]*> [#uses=0] > br i1 false, label %bb, label %bb20 > @@ -50,9 +50,9 @@ > bb420: ; preds = %bb20, %bb20 > ; CHECK: bb420 > ; CHECK: str r{{[0-7]}}, [sp] > -; CHECK: str r{{[0-7]}}, [sp, #+4] > -; CHECK: str r{{[0-7]}}, [sp, #+8] > -; CHECK: str{{(.w)?}} r{{[0-9]+}}, [sp, #+24] > +; CHECK: str r{{[0-7]}}, [sp, #4] > +; CHECK: str r{{[0-7]}}, [sp, #8] > +; CHECK: str{{(.w)?}} r{{[0-9]+}}, [sp, #24] > store %union.rec* null, %union.rec** @zz_hold, align 4 > store %union.rec* null, %union.rec** @zz_res, align 4 > store %union.rec* %x, %union.rec** @zz_hold, align 4 > > Modified: llvm/trunk/test/CodeGen/Thumb2/thumb2-ldr.ll > URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/CodeGen/Thumb2/thumb2-ldr.ll?rev=98745&r1=98744&r2=98745&view=diff > ============================================================================== > --- llvm/trunk/test/CodeGen/Thumb2/thumb2-ldr.ll (original) > +++ llvm/trunk/test/CodeGen/Thumb2/thumb2-ldr.ll Wed Mar 17 12:52:21 2010 > @@ -11,7 +11,7 @@ > define i32 @f2(i32* %v) { > entry: > ; CHECK: f2: > -; CHECK: ldr.w r0, [r0, #+4092] > +; CHECK: ldr.w r0, [r0, #4092] > %tmp2 = getelementptr i32* %v, i32 1023 > %tmp = load i32* %tmp2 > ret i32 %tmp > > Modified: llvm/trunk/test/CodeGen/Thumb2/thumb2-ldrh.ll > URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/CodeGen/Thumb2/thumb2-ldrh.ll?rev=98745&r1=98744&r2=98745&view=diff > ============================================================================== > --- llvm/trunk/test/CodeGen/Thumb2/thumb2-ldrh.ll (original) > +++ llvm/trunk/test/CodeGen/Thumb2/thumb2-ldrh.ll Wed Mar 17 12:52:21 2010 > @@ -11,7 +11,7 @@ > define i16 @f2(i16* %v) { > entry: > ; CHECK: f2: > -; CHECK: ldrh.w r0, [r0, #+2046] > +; CHECK: ldrh.w r0, [r0, #2046] > %tmp2 = getelementptr i16* %v, i16 1023 > %tmp = load i16* %tmp2 > ret i16 %tmp > > Modified: llvm/trunk/test/CodeGen/Thumb2/thumb2-str.ll > URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/CodeGen/Thumb2/thumb2-str.ll?rev=98745&r1=98744&r2=98745&view=diff > ============================================================================== > --- llvm/trunk/test/CodeGen/Thumb2/thumb2-str.ll (original) > +++ llvm/trunk/test/CodeGen/Thumb2/thumb2-str.ll Wed Mar 17 12:52:21 2010 > @@ -9,7 +9,7 @@ > > define i32 @f2(i32 %a, i32* %v) { > ; CHECK: f2: > -; CHECK: str.w r0, [r1, #+4092] > +; CHECK: str.w r0, [r1, #4092] > %tmp2 = getelementptr i32* %v, i32 1023 > store i32 %a, i32* %tmp2 > ret i32 %a > > Modified: llvm/trunk/test/CodeGen/Thumb2/thumb2-str_pre.ll > URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/CodeGen/Thumb2/thumb2-str_pre.ll?rev=98745&r1=98744&r2=98745&view=diff > ============================================================================== > --- llvm/trunk/test/CodeGen/Thumb2/thumb2-str_pre.ll (original) > +++ llvm/trunk/test/CodeGen/Thumb2/thumb2-str_pre.ll Wed Mar 17 12:52:21 2010 > @@ -2,7 +2,7 @@ > > define void @test1(i32* %X, i32* %A, i32** %dest) { > ; CHECK: test1 > -; CHECK: str r1, [r0, #+16]! > +; CHECK: str r1, [r0, #16]! > %B = load i32* %A ; [#uses=1] > %Y = getelementptr i32* %X, i32 4 ; [#uses=2] > store i32 %B, i32* %Y > @@ -12,7 +12,7 @@ > > define i16* @test2(i16* %X, i32* %A) { > ; CHECK: test2 > -; CHECK: strh r1, [r0, #+8]! > +; CHECK: strh r1, [r0, #8]! > %B = load i32* %A ; [#uses=1] > %Y = getelementptr i16* %X, i32 4 ; [#uses=2] > %tmp = trunc i32 %B to i16 ; [#uses=1] > > Modified: llvm/trunk/test/CodeGen/Thumb2/thumb2-strb.ll > URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/CodeGen/Thumb2/thumb2-strb.ll?rev=98745&r1=98744&r2=98745&view=diff > ============================================================================== > --- llvm/trunk/test/CodeGen/Thumb2/thumb2-strb.ll (original) > +++ llvm/trunk/test/CodeGen/Thumb2/thumb2-strb.ll Wed Mar 17 12:52:21 2010 > @@ -9,7 +9,7 @@ > > define i8 @f2(i8 %a, i8* %v) { > ; CHECK: f2: > -; CHECK: strb.w r0, [r1, #+4092] > +; CHECK: strb.w r0, [r1, #4092] > %tmp2 = getelementptr i8* %v, i32 4092 > store i8 %a, i8* %tmp2 > ret i8 %a > > Modified: llvm/trunk/test/CodeGen/Thumb2/thumb2-strh.ll > URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/CodeGen/Thumb2/thumb2-strh.ll?rev=98745&r1=98744&r2=98745&view=diff > ============================================================================== > --- llvm/trunk/test/CodeGen/Thumb2/thumb2-strh.ll (original) > +++ llvm/trunk/test/CodeGen/Thumb2/thumb2-strh.ll Wed Mar 17 12:52:21 2010 > @@ -9,7 +9,7 @@ > > define i16 @f2(i16 %a, i16* %v) { > ; CHECK: f2: > -; CHECK: strh.w r0, [r1, #+4092] > +; CHECK: strh.w r0, [r1, #4092] > %tmp2 = getelementptr i16* %v, i32 2046 > store i16 %a, i16* %tmp2 > ret i16 %a > > > _______________________________________________ > llvm-commits mailing list > llvm-commits at cs.uiuc.edu > http://lists.cs.uiuc.edu/mailman/listinfo/llvm-commits From sabre at nondot.org Wed Mar 17 13:15:53 2010 From: sabre at nondot.org (Chris Lattner) Date: Wed, 17 Mar 2010 18:15:53 -0000 Subject: [llvm-commits] [llvm] r98748 - /llvm/trunk/docs/ReleaseNotes.html Message-ID: <20100317181553.1CC332A6C12C@llvm.org> Author: lattner Date: Wed Mar 17 13:15:52 2010 New Revision: 98748 URL: http://llvm.org/viewvc/llvm-project?rev=98748&view=rev Log: notes from evan Modified: llvm/trunk/docs/ReleaseNotes.html Modified: llvm/trunk/docs/ReleaseNotes.html URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/docs/ReleaseNotes.html?rev=98748&r1=98747&r2=98748&view=diff ============================================================================== --- llvm/trunk/docs/ReleaseNotes.html (original) +++ llvm/trunk/docs/ReleaseNotes.html Wed Mar 17 13:15:52 2010 @@ -464,13 +464,19 @@ completely llvm-gcc NEON support. Can transcode from GAS to intel syntax with "llvm-mc foo.s -output-asm-variant=1" JIT debug information with GDB 7.0 -New CodeGen Level LICM And CSE (did it make 2.7?) +New CodeGen Level CSE CMake can now run tests, what other improvements? -ARM/Thumb register scavenging improvements? +ARM/Thumb using reg scavenging for stack object address materialization (PEI). New SSAUpdater and MachineSSAUpdater classes for unstructured ssa updating, changed jump threading, GVN, etc to use it which simplified them and speed them up. Combiner-AA improvements, why not on by default? +Pre-regalloc tail duplication +x86 sibcall optimization +New LSR with full strength reduction mode +The most awesome sext / zext optimization pass. ? + + CondProp pass removed (functionality merged into jump threading). AndersAA got removed (from 2.7 or mainline?) From ggreif at gmail.com Wed Mar 17 13:22:08 2010 From: ggreif at gmail.com (Gabor Greif) Date: Wed, 17 Mar 2010 19:22:08 +0100 Subject: [llvm-commits] [llvm] r98634 - /llvm/trunk/unittests/VMCore/InstructionsTest.cpp In-Reply-To: <4BA05B76.80101@mxc.ca> References: <20100316155358.966292A6C12C@llvm.org> <4BA05B76.80101@mxc.ca> Message-ID: On Wed, Mar 17, 2010 at 5:32 AM, Nick Lewycky wrote: > Gabor Greif wrote: >> >> Author: ggreif >> Date: Tue Mar 16 10:53:58 2010 >> New Revision: 98634 >> >> URL: http://llvm.org/viewvc/llvm-project?rev=98634&view=rev >> Log: >> more BranchInst tests >> >> Modified: >> ? ? llvm/trunk/unittests/VMCore/InstructionsTest.cpp >> >> Modified: llvm/trunk/unittests/VMCore/InstructionsTest.cpp >> URL: >> http://llvm.org/viewvc/llvm-project/llvm/trunk/unittests/VMCore/InstructionsTest.cpp?rev=98634&r1=98633&r2=98634&view=diff >> >> ============================================================================== >> --- llvm/trunk/unittests/VMCore/InstructionsTest.cpp (original) >> +++ llvm/trunk/unittests/VMCore/InstructionsTest.cpp Tue Mar 16 10:53:58 >> 2010 >> @@ -50,10 +50,17 @@ >> ? ?// Mandatory BranchInst >> ? ?const BranchInst* b0 = BranchInst::Create(bb0); >> >> + ?EXPECT_TRUE(b0->isUnconditional()); >> + ?EXPECT_FALSE(b0->isConditional()); >> + ?EXPECT_EQ(b0->getNumSuccessors(), 1U); >> + >> ? ?// check num operands >> ? ?EXPECT_EQ(b0->getNumOperands(), 1U); >> >> ? ?EXPECT_NE(b0->op_begin(), b0->op_end()); >> + ?EXPECT_EQ(b0->op_begin() + 1, b0->op_end()); > > Consider using llvm::next(b0->op_begin()) defined in > include/llvm/ADT/STLExtras.h . > > I'm assuming that this test passes for you, but I don't normally expect that > I can take iterator + 1 in LLVM because it often gets me a pointer addition. It does pass, yes. And in this case we actually have pointer addition, because the operands are kept in an array. But nevertheless thanks for the hint, I'll change the code :-) Gabor > > Nick > >> + >> + ?EXPECT_EQ(b0->op_begin() + 1, b0->op_end()); >> >> ? ?const IntegerType* Int1 = IntegerType::get(C, 1); >> ? ?Constant* One = ConstantInt::get(Int1, 1, true); >> @@ -61,6 +68,10 @@ >> ? ?// Conditional BranchInst >> ? ?BranchInst* b1 = BranchInst::Create(bb0, bb1, One); >> >> + ?EXPECT_FALSE(b1->isUnconditional()); >> + ?EXPECT_TRUE(b1->isConditional()); >> + ?EXPECT_EQ(b1->getNumSuccessors(), 2U); >> + >> ? ?// check num operands >> ? ?EXPECT_EQ(b1->getNumOperands(), 3U); >> >> @@ -70,16 +81,19 @@ >> ? ?EXPECT_NE(b, b1->op_end()); >> ? ?EXPECT_EQ(*b, One); >> ? ?EXPECT_EQ(b1->getOperand(0), One); >> + ?EXPECT_EQ(b1->getCondition(), One); >> ? ?++b; >> >> ? ?// check ELSE >> ? ?EXPECT_EQ(*b, bb1); >> ? ?EXPECT_EQ(b1->getOperand(1), bb1); >> + ?EXPECT_EQ(b1->getSuccessor(1), bb1); >> ? ?++b; >> >> ? ?// check THEN >> ? ?EXPECT_EQ(*b, bb0); >> ? ?EXPECT_EQ(b1->getOperand(2), bb0); >> + ?EXPECT_EQ(b1->getSuccessor(0), bb0); >> ? ?++b; >> >> ? ?EXPECT_EQ(b, b1->op_end()); >> @@ -96,6 +110,7 @@ >> ? ?// check THEN >> ? ?EXPECT_EQ(*c, bb1); >> ? ?EXPECT_EQ(b1->getOperand(0), bb1); >> + ?EXPECT_EQ(b1->getSuccessor(0), bb1); >> ? ?++c; >> >> ? ?EXPECT_EQ(c, b1->op_end()); >> >> >> _______________________________________________ >> llvm-commits mailing list >> llvm-commits at cs.uiuc.edu >> http://lists.cs.uiuc.edu/mailman/listinfo/llvm-commits >> > > From andrewl at lenharth.org Wed Mar 17 13:23:06 2010 From: andrewl at lenharth.org (Andrew Lenharth) Date: Wed, 17 Mar 2010 18:23:06 -0000 Subject: [llvm-commits] [poolalloc] r98749 - /poolalloc/trunk/include/dsa/svset.h Message-ID: <20100317182306.4A6752A6C12C@llvm.org> Author: alenhar2 Date: Wed Mar 17 13:23:06 2010 New Revision: 98749 URL: http://llvm.org/viewvc/llvm-project?rev=98749&view=rev Log: fix includes Modified: poolalloc/trunk/include/dsa/svset.h Modified: poolalloc/trunk/include/dsa/svset.h URL: http://llvm.org/viewvc/llvm-project/poolalloc/trunk/include/dsa/svset.h?rev=98749&r1=98748&r2=98749&view=diff ============================================================================== --- poolalloc/trunk/include/dsa/svset.h (original) +++ poolalloc/trunk/include/dsa/svset.h Wed Mar 17 13:23:06 2010 @@ -2,6 +2,8 @@ #define _SV_ORDERED_SET_HH_ 1 #include +#include +#include //////////////////////////////////////////////////////////////////////////////////////////////////// From johnny.chen at apple.com Wed Mar 17 13:32:40 2010 From: johnny.chen at apple.com (Johnny Chen) Date: Wed, 17 Mar 2010 18:32:40 -0000 Subject: [llvm-commits] [llvm] r98751 - /llvm/trunk/lib/Target/ARM/ARMAddressingModes.h Message-ID: <20100317183240.278ED2A6C12C@llvm.org> Author: johnny Date: Wed Mar 17 13:32:39 2010 New Revision: 98751 URL: http://llvm.org/viewvc/llvm-project?rev=98751&view=rev Log: 98745 contains something unrelated to the patch. Remove it from ARMAddressingModes.h. Modified: llvm/trunk/lib/Target/ARM/ARMAddressingModes.h Modified: llvm/trunk/lib/Target/ARM/ARMAddressingModes.h URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Target/ARM/ARMAddressingModes.h?rev=98751&r1=98750&r2=98751&view=diff ============================================================================== --- llvm/trunk/lib/Target/ARM/ARMAddressingModes.h (original) +++ llvm/trunk/lib/Target/ARM/ARMAddressingModes.h Wed Mar 17 13:32:39 2010 @@ -131,20 +131,6 @@ return (Imm >> 8) * 2; } - /// getSOImmValOneRotate - Try to handle Imm with an immediate shifter - /// operand, computing the rotate amount to use. If this immediate value - /// cannot be handled with a single shifter-op, return 0. - static inline unsigned getSOImmValOneRotate(unsigned Imm) { - // A5.2.4 Constants with multiple encodings - // The lowest unsigned value of rotation wins! - for (unsigned R = 1; R <= 15; ++R) - if ((Imm & rotr32(~255U, 2*R)) == 0) - return 2*R; - - // Failed to find a suitable rotate amount. - return 0; - } - /// getSOImmValRotate - Try to handle Imm with an immediate shifter operand, /// computing the rotate amount to use. If this immediate value cannot be /// handled with a single shifter-op, determine a good rotate amount that will @@ -197,7 +183,7 @@ // of zero. if ((Arg & ~255U) == 0) return Arg; - unsigned RotAmt = getSOImmValOneRotate(Arg); + unsigned RotAmt = getSOImmValRotate(Arg); // If this cannot be handled with a single shifter_op, bail out. if (rotr32(~255U, RotAmt) & Arg) From andrewl at lenharth.org Wed Mar 17 13:33:00 2010 From: andrewl at lenharth.org (Andrew Lenharth) Date: Wed, 17 Mar 2010 18:33:00 -0000 Subject: [llvm-commits] [llvm] r98752 - /llvm/trunk/include/llvm/ADT/EquivalenceClasses.h Message-ID: <20100317183300.490EC2A6C12C@llvm.org> Author: alenhar2 Date: Wed Mar 17 13:33:00 2010 New Revision: 98752 URL: http://llvm.org/viewvc/llvm-project?rev=98752&view=rev Log: missing include Modified: llvm/trunk/include/llvm/ADT/EquivalenceClasses.h Modified: llvm/trunk/include/llvm/ADT/EquivalenceClasses.h URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/ADT/EquivalenceClasses.h?rev=98752&r1=98751&r2=98752&view=diff ============================================================================== --- llvm/trunk/include/llvm/ADT/EquivalenceClasses.h (original) +++ llvm/trunk/include/llvm/ADT/EquivalenceClasses.h Wed Mar 17 13:33:00 2010 @@ -17,6 +17,7 @@ #include "llvm/System/DataTypes.h" #include +#include namespace llvm { From bob.wilson at apple.com Wed Mar 17 13:43:25 2010 From: bob.wilson at apple.com (Bob Wilson) Date: Wed, 17 Mar 2010 18:43:25 -0000 Subject: [llvm-commits] [llvm] r98753 - /llvm/trunk/include/llvm/Target/TargetLowering.h Message-ID: <20100317184325.BFA292A6C12C@llvm.org> Author: bwilson Date: Wed Mar 17 13:43:25 2010 New Revision: 98753 URL: http://llvm.org/viewvc/llvm-project?rev=98753&view=rev Log: Remove an unnecessary (and misspelled) typedef. Tweak whitespace. Modified: llvm/trunk/include/llvm/Target/TargetLowering.h Modified: llvm/trunk/include/llvm/Target/TargetLowering.h URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/Target/TargetLowering.h?rev=98753&r1=98752&r2=98753&view=diff ============================================================================== --- llvm/trunk/include/llvm/Target/TargetLowering.h (original) +++ llvm/trunk/include/llvm/Target/TargetLowering.h Wed Mar 17 13:43:25 2010 @@ -307,7 +307,7 @@ /// intrinsic will need to map to a MemIntrinsicNode (touches memory). If /// this is the case, it returns true and store the intrinsic /// information into the IntrinsicInfo that was passed to the function. - typedef struct IntrinsicInfo { + struct IntrinsicInfo { unsigned opc; // target opcode EVT memVT; // memory VT const Value* ptrVal; // value representing memory location @@ -316,9 +316,9 @@ bool vol; // is volatile? bool readMem; // reads memory? bool writeMem; // writes memory? - } IntrinisicInfo; + }; - virtual bool getTgtMemIntrinsic(IntrinsicInfo& Info, + virtual bool getTgtMemIntrinsic(IntrinsicInfo &Info, CallInst &I, unsigned Intrinsic) { return false; } From gohman at apple.com Wed Mar 17 13:51:01 2010 From: gohman at apple.com (Dan Gohman) Date: Wed, 17 Mar 2010 18:51:01 -0000 Subject: [llvm-commits] [llvm] r98755 - in /llvm/trunk: include/llvm/Analysis/ScalarEvolutionExpressions.h lib/Analysis/ScalarEvolution.cpp lib/Analysis/ScalarEvolutionExpander.cpp Message-ID: <20100317185101.E86CB2A6C12C@llvm.org> Author: djg Date: Wed Mar 17 13:51:01 2010 New Revision: 98755 URL: http://llvm.org/viewvc/llvm-project?rev=98755&view=rev Log: Change SCEVNAryExpr's operand array from a SmallVector to a plain pointer and length, and allocate the arrays in ScalarEvolution's BumpPtrAllocator, so that they get released when their owning SCEV gets released. SCEVs are immutable, so they don't need to worry about operand array resizing. This fixes a memory leak reported in PR6637. Modified: llvm/trunk/include/llvm/Analysis/ScalarEvolutionExpressions.h llvm/trunk/lib/Analysis/ScalarEvolution.cpp llvm/trunk/lib/Analysis/ScalarEvolutionExpander.cpp Modified: llvm/trunk/include/llvm/Analysis/ScalarEvolutionExpressions.h URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/Analysis/ScalarEvolutionExpressions.h?rev=98755&r1=98754&r2=98755&view=diff ============================================================================== --- llvm/trunk/include/llvm/Analysis/ScalarEvolutionExpressions.h (original) +++ llvm/trunk/include/llvm/Analysis/ScalarEvolutionExpressions.h Wed Mar 17 13:51:01 2010 @@ -180,25 +180,27 @@ /// class SCEVNAryExpr : public SCEV { protected: - SmallVector Operands; + // Since SCEVs are immutable, ScalarEvolution allocates operand + // arrays with its SCEVAllocator, so this class just needs a simple + // pointer rather than a more elaborate vector-like data structure. + // This also avoids the need for a non-trivial destructor. + const SCEV *const *Operands; + size_t NumOperands; SCEVNAryExpr(const FoldingSetNodeID &ID, - enum SCEVTypes T, const SmallVectorImpl &ops) - : SCEV(ID, T), Operands(ops.begin(), ops.end()) {} + enum SCEVTypes T, const SCEV *const *O, size_t N) + : SCEV(ID, T), Operands(O), NumOperands(N) {} public: - unsigned getNumOperands() const { return (unsigned)Operands.size(); } + size_t getNumOperands() const { return NumOperands; } const SCEV *getOperand(unsigned i) const { - assert(i < Operands.size() && "Operand index out of range!"); + assert(i < NumOperands && "Operand index out of range!"); return Operands[i]; } - const SmallVectorImpl &getOperands() const { - return Operands; - } - typedef SmallVectorImpl::const_iterator op_iterator; - op_iterator op_begin() const { return Operands.begin(); } - op_iterator op_end() const { return Operands.end(); } + typedef const SCEV *const *op_iterator; + op_iterator op_begin() const { return Operands; } + op_iterator op_end() const { return Operands + NumOperands; } virtual bool isLoopInvariant(const Loop *L) const { for (unsigned i = 0, e = getNumOperands(); i != e; ++i) @@ -262,8 +264,8 @@ protected: SCEVCommutativeExpr(const FoldingSetNodeID &ID, enum SCEVTypes T, - const SmallVectorImpl &ops) - : SCEVNAryExpr(ID, T, ops) {} + const SCEV *const *O, size_t N) + : SCEVNAryExpr(ID, T, O, N) {} public: virtual const char *getOperationStr() const = 0; @@ -288,8 +290,8 @@ friend class ScalarEvolution; SCEVAddExpr(const FoldingSetNodeID &ID, - const SmallVectorImpl &ops) - : SCEVCommutativeExpr(ID, scAddExpr, ops) { + const SCEV *const *O, size_t N) + : SCEVCommutativeExpr(ID, scAddExpr, O, N) { } public: @@ -316,8 +318,8 @@ friend class ScalarEvolution; SCEVMulExpr(const FoldingSetNodeID &ID, - const SmallVectorImpl &ops) - : SCEVCommutativeExpr(ID, scMulExpr, ops) { + const SCEV *const *O, size_t N) + : SCEVCommutativeExpr(ID, scMulExpr, O, N) { } public: @@ -390,9 +392,9 @@ const Loop *L; SCEVAddRecExpr(const FoldingSetNodeID &ID, - const SmallVectorImpl &ops, const Loop *l) - : SCEVNAryExpr(ID, scAddRecExpr, ops), L(l) { - for (size_t i = 0, e = Operands.size(); i != e; ++i) + const SCEV *const *O, size_t N, const Loop *l) + : SCEVNAryExpr(ID, scAddRecExpr, O, N), L(l) { + for (size_t i = 0, e = NumOperands; i != e; ++i) assert(Operands[i]->isLoopInvariant(l) && "Operands of AddRec must be loop-invariant!"); } @@ -472,8 +474,8 @@ friend class ScalarEvolution; SCEVSMaxExpr(const FoldingSetNodeID &ID, - const SmallVectorImpl &ops) - : SCEVCommutativeExpr(ID, scSMaxExpr, ops) { + const SCEV *const *O, size_t N) + : SCEVCommutativeExpr(ID, scSMaxExpr, O, N) { // Max never overflows. setHasNoUnsignedWrap(true); setHasNoSignedWrap(true); @@ -497,8 +499,8 @@ friend class ScalarEvolution; SCEVUMaxExpr(const FoldingSetNodeID &ID, - const SmallVectorImpl &ops) - : SCEVCommutativeExpr(ID, scUMaxExpr, ops) { + const SCEV *const *O, size_t N) + : SCEVCommutativeExpr(ID, scUMaxExpr, O, N) { // Max never overflows. setHasNoUnsignedWrap(true); setHasNoSignedWrap(true); Modified: llvm/trunk/lib/Analysis/ScalarEvolution.cpp URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Analysis/ScalarEvolution.cpp?rev=98755&r1=98754&r2=98755&view=diff ============================================================================== --- llvm/trunk/lib/Analysis/ScalarEvolution.cpp (original) +++ llvm/trunk/lib/Analysis/ScalarEvolution.cpp Wed Mar 17 13:51:01 2010 @@ -248,10 +248,10 @@ } void SCEVCommutativeExpr::print(raw_ostream &OS) const { - assert(Operands.size() > 1 && "This plus expr shouldn't exist!"); + assert(NumOperands > 1 && "This plus expr shouldn't exist!"); const char *OpStr = getOperationStr(); OS << "(" << *Operands[0]; - for (unsigned i = 1, e = Operands.size(); i != e; ++i) + for (unsigned i = 1, e = NumOperands; i != e; ++i) OS << OpStr << *Operands[i]; OS << ")"; } @@ -329,7 +329,7 @@ void SCEVAddRecExpr::print(raw_ostream &OS) const { OS << "{" << *Operands[0]; - for (unsigned i = 1, e = Operands.size(); i != e; ++i) + for (unsigned i = 1, e = NumOperands; i != e; ++i) OS << ",+," << *Operands[i]; OS << "}<"; WriteAsOperand(OS, L->getHeader(), /*PrintType=*/false); @@ -1202,23 +1202,23 @@ CollectAddOperandsWithScales(DenseMap &M, SmallVector &NewOps, APInt &AccumulatedConstant, - const SmallVectorImpl &Ops, + const SCEV *const *Ops, size_t NumOperands, const APInt &Scale, ScalarEvolution &SE) { bool Interesting = false; // Iterate over the add operands. - for (unsigned i = 0, e = Ops.size(); i != e; ++i) { + for (unsigned i = 0, e = NumOperands; i != e; ++i) { const SCEVMulExpr *Mul = dyn_cast(Ops[i]); if (Mul && isa(Mul->getOperand(0))) { APInt NewScale = Scale * cast(Mul->getOperand(0))->getValue()->getValue(); if (Mul->getNumOperands() == 2 && isa(Mul->getOperand(1))) { // A multiplication of a constant with another add; recurse. + const SCEVAddExpr *Add = cast(Mul->getOperand(1)); Interesting |= CollectAddOperandsWithScales(M, NewOps, AccumulatedConstant, - cast(Mul->getOperand(1)) - ->getOperands(), + Add->op_begin(), Add->getNumOperands(), NewScale, SE); } else { // A multiplication of a constant with some other value. Update @@ -1427,7 +1427,8 @@ SmallVector NewOps; APInt AccumulatedConstant(BitWidth, 0); if (CollectAddOperandsWithScales(M, NewOps, AccumulatedConstant, - Ops, APInt(BitWidth, 1), *this)) { + Ops.data(), Ops.size(), + APInt(BitWidth, 1), *this)) { // Some interesting folding opportunity is present, so its worthwhile to // re-generate the operands list. Group the operands by constant scale, // to avoid multiplying by the same constant scale multiple times. @@ -1612,7 +1613,9 @@ static_cast(UniqueSCEVs.FindNodeOrInsertPos(ID, IP)); if (!S) { S = SCEVAllocator.Allocate(); - new (S) SCEVAddExpr(ID, Ops); + const SCEV **O = SCEVAllocator.Allocate(Ops.size()); + std::uninitialized_copy(Ops.begin(), Ops.end(), O); + new (S) SCEVAddExpr(ID, O, Ops.size()); UniqueSCEVs.InsertNode(S, IP); } if (HasNUW) S->setHasNoUnsignedWrap(true); @@ -1820,7 +1823,9 @@ static_cast(UniqueSCEVs.FindNodeOrInsertPos(ID, IP)); if (!S) { S = SCEVAllocator.Allocate(); - new (S) SCEVMulExpr(ID, Ops); + const SCEV **O = SCEVAllocator.Allocate(Ops.size()); + std::uninitialized_copy(Ops.begin(), Ops.end(), O); + new (S) SCEVMulExpr(ID, O, Ops.size()); UniqueSCEVs.InsertNode(S, IP); } if (HasNUW) S->setHasNoUnsignedWrap(true); @@ -1880,9 +1885,7 @@ const SCEV *Op = M->getOperand(i); const SCEV *Div = getUDivExpr(Op, RHSC); if (!isa(Div) && getMulExpr(Div, RHSC) == Op) { - const SmallVectorImpl &MOperands = M->getOperands(); - Operands = SmallVector(MOperands.begin(), - MOperands.end()); + Operands = SmallVector(M->op_begin(), M->op_end()); Operands[i] = Div; return getMulExpr(Operands); } @@ -2031,7 +2034,9 @@ static_cast(UniqueSCEVs.FindNodeOrInsertPos(ID, IP)); if (!S) { S = SCEVAllocator.Allocate(); - new (S) SCEVAddRecExpr(ID, Operands, L); + const SCEV **O = SCEVAllocator.Allocate(Operands.size()); + std::uninitialized_copy(Operands.begin(), Operands.end(), O); + new (S) SCEVAddRecExpr(ID, O, Operands.size(), L); UniqueSCEVs.InsertNode(S, IP); } if (HasNUW) S->setHasNoUnsignedWrap(true); @@ -2131,7 +2136,9 @@ void *IP = 0; if (const SCEV *S = UniqueSCEVs.FindNodeOrInsertPos(ID, IP)) return S; SCEV *S = SCEVAllocator.Allocate(); - new (S) SCEVSMaxExpr(ID, Ops); + const SCEV **O = SCEVAllocator.Allocate(Ops.size()); + std::uninitialized_copy(Ops.begin(), Ops.end(), O); + new (S) SCEVSMaxExpr(ID, O, Ops.size()); UniqueSCEVs.InsertNode(S, IP); return S; } @@ -2228,7 +2235,9 @@ void *IP = 0; if (const SCEV *S = UniqueSCEVs.FindNodeOrInsertPos(ID, IP)) return S; SCEV *S = SCEVAllocator.Allocate(); - new (S) SCEVUMaxExpr(ID, Ops); + const SCEV **O = SCEVAllocator.Allocate(Ops.size()); + std::uninitialized_copy(Ops.begin(), Ops.end(), O); + new (S) SCEVUMaxExpr(ID, O, Ops.size()); UniqueSCEVs.InsertNode(S, IP); return S; } Modified: llvm/trunk/lib/Analysis/ScalarEvolutionExpander.cpp URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Analysis/ScalarEvolutionExpander.cpp?rev=98755&r1=98754&r2=98755&view=diff ============================================================================== --- llvm/trunk/lib/Analysis/ScalarEvolutionExpander.cpp (original) +++ llvm/trunk/lib/Analysis/ScalarEvolutionExpander.cpp Wed Mar 17 13:51:01 2010 @@ -232,9 +232,7 @@ const SCEVConstant *FC = cast(Factor); if (const SCEVConstant *C = dyn_cast(M->getOperand(0))) if (!C->getValue()->getValue().srem(FC->getValue()->getValue())) { - const SmallVectorImpl &MOperands = M->getOperands(); - SmallVector NewMulOps(MOperands.begin(), - MOperands.end()); + SmallVector NewMulOps(M->op_begin(), M->op_end()); NewMulOps[0] = SE.getConstant(C->getValue()->getValue().sdiv( FC->getValue()->getValue())); @@ -249,9 +247,7 @@ const SCEV *Remainder = SE.getIntegerSCEV(0, SOp->getType()); if (FactorOutConstant(SOp, Remainder, Factor, SE, TD) && Remainder->isZero()) { - const SmallVectorImpl &MOperands = M->getOperands(); - SmallVector NewMulOps(MOperands.begin(), - MOperands.end()); + SmallVector NewMulOps(M->op_begin(), M->op_end()); NewMulOps[i] = SOp; S = SE.getMulExpr(NewMulOps); return true; @@ -297,13 +293,11 @@ SE.getAddExpr(NoAddRecs); // If it returned an add, use the operands. Otherwise it simplified // the sum into a single value, so just use that. + Ops.clear(); if (const SCEVAddExpr *Add = dyn_cast(Sum)) - Ops = Add->getOperands(); - else { - Ops.clear(); - if (!Sum->isZero()) - Ops.push_back(Sum); - } + Ops.insert(Ops.end(), Add->op_begin(), Add->op_begin()); + else if (!Sum->isZero()) + Ops.push_back(Sum); // Then append the addrecs. Ops.insert(Ops.end(), AddRecs.begin(), AddRecs.end()); } @@ -1060,10 +1054,9 @@ if (CanonicalIV && SE.getTypeSizeInBits(CanonicalIV->getType()) > SE.getTypeSizeInBits(Ty)) { - const SmallVectorImpl &Ops = S->getOperands(); - SmallVector NewOps(Ops.size()); - for (unsigned i = 0, e = Ops.size(); i != e; ++i) - NewOps[i] = SE.getAnyExtendExpr(Ops[i], CanonicalIV->getType()); + SmallVector NewOps(S->getNumOperands()); + for (unsigned i = 0, e = S->getNumOperands(); i != e; ++i) + NewOps[i] = SE.getAnyExtendExpr(S->op_begin()[i], CanonicalIV->getType()); Value *V = expand(SE.getAddRecExpr(NewOps, S->getLoop())); BasicBlock *SaveInsertBB = Builder.GetInsertBlock(); BasicBlock::iterator SaveInsertPt = Builder.GetInsertPoint(); @@ -1078,8 +1071,7 @@ // {X,+,F} --> X + {0,+,F} if (!S->getStart()->isZero()) { - const SmallVectorImpl &SOperands = S->getOperands(); - SmallVector NewOps(SOperands.begin(), SOperands.end()); + SmallVector NewOps(S->op_begin(), S->op_end()); NewOps[0] = SE.getIntegerSCEV(0, Ty); const SCEV *Rest = SE.getAddRecExpr(NewOps, L); From ggreif at gmail.com Wed Mar 17 14:27:31 2010 From: ggreif at gmail.com (Gabor Greif) Date: Wed, 17 Mar 2010 19:27:31 -0000 Subject: [llvm-commits] [llvm] r98761 - /llvm/trunk/unittests/VMCore/InstructionsTest.cpp Message-ID: <20100317192731.4D75D2A6C12C@llvm.org> Author: ggreif Date: Wed Mar 17 14:27:31 2010 New Revision: 98761 URL: http://llvm.org/viewvc/llvm-project?rev=98761&view=rev Log: feedback from Nick Modified: llvm/trunk/unittests/VMCore/InstructionsTest.cpp Modified: llvm/trunk/unittests/VMCore/InstructionsTest.cpp URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/unittests/VMCore/InstructionsTest.cpp?rev=98761&r1=98760&r2=98761&view=diff ============================================================================== --- llvm/trunk/unittests/VMCore/InstructionsTest.cpp (original) +++ llvm/trunk/unittests/VMCore/InstructionsTest.cpp Wed Mar 17 14:27:31 2010 @@ -11,6 +11,7 @@ #include "llvm/BasicBlock.h" #include "llvm/DerivedTypes.h" #include "llvm/LLVMContext.h" +#include "llvm/ADT/STLExtras.h" #include "gtest/gtest.h" namespace llvm { @@ -60,7 +61,7 @@ EXPECT_NE(b0->op_begin(), b0->op_end()); EXPECT_EQ(b0->op_begin() + 1, b0->op_end()); - EXPECT_EQ(b0->op_begin() + 1, b0->op_end()); + EXPECT_EQ(next(b0->op_begin()), b0->op_end()); const IntegerType* Int1 = IntegerType::get(C, 1); Constant* One = ConstantInt::get(Int1, 1, true); From gohman at apple.com Wed Mar 17 14:54:53 2010 From: gohman at apple.com (Dan Gohman) Date: Wed, 17 Mar 2010 19:54:53 -0000 Subject: [llvm-commits] [llvm] r98762 - in /llvm/trunk: include/llvm/Analysis/ScalarEvolutionExpressions.h lib/Analysis/ScalarEvolution.cpp lib/Analysis/ScalarEvolutionExpander.cpp Message-ID: <20100317195453.D65BC2A6C12C@llvm.org> Author: djg Date: Wed Mar 17 14:54:53 2010 New Revision: 98762 URL: http://llvm.org/viewvc/llvm-project?rev=98762&view=rev Log: Revert 98755, which may be causing trouble. Modified: llvm/trunk/include/llvm/Analysis/ScalarEvolutionExpressions.h llvm/trunk/lib/Analysis/ScalarEvolution.cpp llvm/trunk/lib/Analysis/ScalarEvolutionExpander.cpp Modified: llvm/trunk/include/llvm/Analysis/ScalarEvolutionExpressions.h URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/Analysis/ScalarEvolutionExpressions.h?rev=98762&r1=98761&r2=98762&view=diff ============================================================================== --- llvm/trunk/include/llvm/Analysis/ScalarEvolutionExpressions.h (original) +++ llvm/trunk/include/llvm/Analysis/ScalarEvolutionExpressions.h Wed Mar 17 14:54:53 2010 @@ -180,27 +180,25 @@ /// class SCEVNAryExpr : public SCEV { protected: - // Since SCEVs are immutable, ScalarEvolution allocates operand - // arrays with its SCEVAllocator, so this class just needs a simple - // pointer rather than a more elaborate vector-like data structure. - // This also avoids the need for a non-trivial destructor. - const SCEV *const *Operands; - size_t NumOperands; + SmallVector Operands; SCEVNAryExpr(const FoldingSetNodeID &ID, - enum SCEVTypes T, const SCEV *const *O, size_t N) - : SCEV(ID, T), Operands(O), NumOperands(N) {} + enum SCEVTypes T, const SmallVectorImpl &ops) + : SCEV(ID, T), Operands(ops.begin(), ops.end()) {} public: - size_t getNumOperands() const { return NumOperands; } + unsigned getNumOperands() const { return (unsigned)Operands.size(); } const SCEV *getOperand(unsigned i) const { - assert(i < NumOperands && "Operand index out of range!"); + assert(i < Operands.size() && "Operand index out of range!"); return Operands[i]; } - typedef const SCEV *const *op_iterator; - op_iterator op_begin() const { return Operands; } - op_iterator op_end() const { return Operands + NumOperands; } + const SmallVectorImpl &getOperands() const { + return Operands; + } + typedef SmallVectorImpl::const_iterator op_iterator; + op_iterator op_begin() const { return Operands.begin(); } + op_iterator op_end() const { return Operands.end(); } virtual bool isLoopInvariant(const Loop *L) const { for (unsigned i = 0, e = getNumOperands(); i != e; ++i) @@ -264,8 +262,8 @@ protected: SCEVCommutativeExpr(const FoldingSetNodeID &ID, enum SCEVTypes T, - const SCEV *const *O, size_t N) - : SCEVNAryExpr(ID, T, O, N) {} + const SmallVectorImpl &ops) + : SCEVNAryExpr(ID, T, ops) {} public: virtual const char *getOperationStr() const = 0; @@ -290,8 +288,8 @@ friend class ScalarEvolution; SCEVAddExpr(const FoldingSetNodeID &ID, - const SCEV *const *O, size_t N) - : SCEVCommutativeExpr(ID, scAddExpr, O, N) { + const SmallVectorImpl &ops) + : SCEVCommutativeExpr(ID, scAddExpr, ops) { } public: @@ -318,8 +316,8 @@ friend class ScalarEvolution; SCEVMulExpr(const FoldingSetNodeID &ID, - const SCEV *const *O, size_t N) - : SCEVCommutativeExpr(ID, scMulExpr, O, N) { + const SmallVectorImpl &ops) + : SCEVCommutativeExpr(ID, scMulExpr, ops) { } public: @@ -392,9 +390,9 @@ const Loop *L; SCEVAddRecExpr(const FoldingSetNodeID &ID, - const SCEV *const *O, size_t N, const Loop *l) - : SCEVNAryExpr(ID, scAddRecExpr, O, N), L(l) { - for (size_t i = 0, e = NumOperands; i != e; ++i) + const SmallVectorImpl &ops, const Loop *l) + : SCEVNAryExpr(ID, scAddRecExpr, ops), L(l) { + for (size_t i = 0, e = Operands.size(); i != e; ++i) assert(Operands[i]->isLoopInvariant(l) && "Operands of AddRec must be loop-invariant!"); } @@ -474,8 +472,8 @@ friend class ScalarEvolution; SCEVSMaxExpr(const FoldingSetNodeID &ID, - const SCEV *const *O, size_t N) - : SCEVCommutativeExpr(ID, scSMaxExpr, O, N) { + const SmallVectorImpl &ops) + : SCEVCommutativeExpr(ID, scSMaxExpr, ops) { // Max never overflows. setHasNoUnsignedWrap(true); setHasNoSignedWrap(true); @@ -499,8 +497,8 @@ friend class ScalarEvolution; SCEVUMaxExpr(const FoldingSetNodeID &ID, - const SCEV *const *O, size_t N) - : SCEVCommutativeExpr(ID, scUMaxExpr, O, N) { + const SmallVectorImpl &ops) + : SCEVCommutativeExpr(ID, scUMaxExpr, ops) { // Max never overflows. setHasNoUnsignedWrap(true); setHasNoSignedWrap(true); Modified: llvm/trunk/lib/Analysis/ScalarEvolution.cpp URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Analysis/ScalarEvolution.cpp?rev=98762&r1=98761&r2=98762&view=diff ============================================================================== --- llvm/trunk/lib/Analysis/ScalarEvolution.cpp (original) +++ llvm/trunk/lib/Analysis/ScalarEvolution.cpp Wed Mar 17 14:54:53 2010 @@ -248,10 +248,10 @@ } void SCEVCommutativeExpr::print(raw_ostream &OS) const { - assert(NumOperands > 1 && "This plus expr shouldn't exist!"); + assert(Operands.size() > 1 && "This plus expr shouldn't exist!"); const char *OpStr = getOperationStr(); OS << "(" << *Operands[0]; - for (unsigned i = 1, e = NumOperands; i != e; ++i) + for (unsigned i = 1, e = Operands.size(); i != e; ++i) OS << OpStr << *Operands[i]; OS << ")"; } @@ -329,7 +329,7 @@ void SCEVAddRecExpr::print(raw_ostream &OS) const { OS << "{" << *Operands[0]; - for (unsigned i = 1, e = NumOperands; i != e; ++i) + for (unsigned i = 1, e = Operands.size(); i != e; ++i) OS << ",+," << *Operands[i]; OS << "}<"; WriteAsOperand(OS, L->getHeader(), /*PrintType=*/false); @@ -1202,23 +1202,23 @@ CollectAddOperandsWithScales(DenseMap &M, SmallVector &NewOps, APInt &AccumulatedConstant, - const SCEV *const *Ops, size_t NumOperands, + const SmallVectorImpl &Ops, const APInt &Scale, ScalarEvolution &SE) { bool Interesting = false; // Iterate over the add operands. - for (unsigned i = 0, e = NumOperands; i != e; ++i) { + for (unsigned i = 0, e = Ops.size(); i != e; ++i) { const SCEVMulExpr *Mul = dyn_cast(Ops[i]); if (Mul && isa(Mul->getOperand(0))) { APInt NewScale = Scale * cast(Mul->getOperand(0))->getValue()->getValue(); if (Mul->getNumOperands() == 2 && isa(Mul->getOperand(1))) { // A multiplication of a constant with another add; recurse. - const SCEVAddExpr *Add = cast(Mul->getOperand(1)); Interesting |= CollectAddOperandsWithScales(M, NewOps, AccumulatedConstant, - Add->op_begin(), Add->getNumOperands(), + cast(Mul->getOperand(1)) + ->getOperands(), NewScale, SE); } else { // A multiplication of a constant with some other value. Update @@ -1427,8 +1427,7 @@ SmallVector NewOps; APInt AccumulatedConstant(BitWidth, 0); if (CollectAddOperandsWithScales(M, NewOps, AccumulatedConstant, - Ops.data(), Ops.size(), - APInt(BitWidth, 1), *this)) { + Ops, APInt(BitWidth, 1), *this)) { // Some interesting folding opportunity is present, so its worthwhile to // re-generate the operands list. Group the operands by constant scale, // to avoid multiplying by the same constant scale multiple times. @@ -1613,9 +1612,7 @@ static_cast(UniqueSCEVs.FindNodeOrInsertPos(ID, IP)); if (!S) { S = SCEVAllocator.Allocate(); - const SCEV **O = SCEVAllocator.Allocate(Ops.size()); - std::uninitialized_copy(Ops.begin(), Ops.end(), O); - new (S) SCEVAddExpr(ID, O, Ops.size()); + new (S) SCEVAddExpr(ID, Ops); UniqueSCEVs.InsertNode(S, IP); } if (HasNUW) S->setHasNoUnsignedWrap(true); @@ -1823,9 +1820,7 @@ static_cast(UniqueSCEVs.FindNodeOrInsertPos(ID, IP)); if (!S) { S = SCEVAllocator.Allocate(); - const SCEV **O = SCEVAllocator.Allocate(Ops.size()); - std::uninitialized_copy(Ops.begin(), Ops.end(), O); - new (S) SCEVMulExpr(ID, O, Ops.size()); + new (S) SCEVMulExpr(ID, Ops); UniqueSCEVs.InsertNode(S, IP); } if (HasNUW) S->setHasNoUnsignedWrap(true); @@ -1885,7 +1880,9 @@ const SCEV *Op = M->getOperand(i); const SCEV *Div = getUDivExpr(Op, RHSC); if (!isa(Div) && getMulExpr(Div, RHSC) == Op) { - Operands = SmallVector(M->op_begin(), M->op_end()); + const SmallVectorImpl &MOperands = M->getOperands(); + Operands = SmallVector(MOperands.begin(), + MOperands.end()); Operands[i] = Div; return getMulExpr(Operands); } @@ -2034,9 +2031,7 @@ static_cast(UniqueSCEVs.FindNodeOrInsertPos(ID, IP)); if (!S) { S = SCEVAllocator.Allocate(); - const SCEV **O = SCEVAllocator.Allocate(Operands.size()); - std::uninitialized_copy(Operands.begin(), Operands.end(), O); - new (S) SCEVAddRecExpr(ID, O, Operands.size(), L); + new (S) SCEVAddRecExpr(ID, Operands, L); UniqueSCEVs.InsertNode(S, IP); } if (HasNUW) S->setHasNoUnsignedWrap(true); @@ -2136,9 +2131,7 @@ void *IP = 0; if (const SCEV *S = UniqueSCEVs.FindNodeOrInsertPos(ID, IP)) return S; SCEV *S = SCEVAllocator.Allocate(); - const SCEV **O = SCEVAllocator.Allocate(Ops.size()); - std::uninitialized_copy(Ops.begin(), Ops.end(), O); - new (S) SCEVSMaxExpr(ID, O, Ops.size()); + new (S) SCEVSMaxExpr(ID, Ops); UniqueSCEVs.InsertNode(S, IP); return S; } @@ -2235,9 +2228,7 @@ void *IP = 0; if (const SCEV *S = UniqueSCEVs.FindNodeOrInsertPos(ID, IP)) return S; SCEV *S = SCEVAllocator.Allocate(); - const SCEV **O = SCEVAllocator.Allocate(Ops.size()); - std::uninitialized_copy(Ops.begin(), Ops.end(), O); - new (S) SCEVUMaxExpr(ID, O, Ops.size()); + new (S) SCEVUMaxExpr(ID, Ops); UniqueSCEVs.InsertNode(S, IP); return S; } Modified: llvm/trunk/lib/Analysis/ScalarEvolutionExpander.cpp URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Analysis/ScalarEvolutionExpander.cpp?rev=98762&r1=98761&r2=98762&view=diff ============================================================================== --- llvm/trunk/lib/Analysis/ScalarEvolutionExpander.cpp (original) +++ llvm/trunk/lib/Analysis/ScalarEvolutionExpander.cpp Wed Mar 17 14:54:53 2010 @@ -232,7 +232,9 @@ const SCEVConstant *FC = cast(Factor); if (const SCEVConstant *C = dyn_cast(M->getOperand(0))) if (!C->getValue()->getValue().srem(FC->getValue()->getValue())) { - SmallVector NewMulOps(M->op_begin(), M->op_end()); + const SmallVectorImpl &MOperands = M->getOperands(); + SmallVector NewMulOps(MOperands.begin(), + MOperands.end()); NewMulOps[0] = SE.getConstant(C->getValue()->getValue().sdiv( FC->getValue()->getValue())); @@ -247,7 +249,9 @@ const SCEV *Remainder = SE.getIntegerSCEV(0, SOp->getType()); if (FactorOutConstant(SOp, Remainder, Factor, SE, TD) && Remainder->isZero()) { - SmallVector NewMulOps(M->op_begin(), M->op_end()); + const SmallVectorImpl &MOperands = M->getOperands(); + SmallVector NewMulOps(MOperands.begin(), + MOperands.end()); NewMulOps[i] = SOp; S = SE.getMulExpr(NewMulOps); return true; @@ -293,11 +297,13 @@ SE.getAddExpr(NoAddRecs); // If it returned an add, use the operands. Otherwise it simplified // the sum into a single value, so just use that. - Ops.clear(); if (const SCEVAddExpr *Add = dyn_cast(Sum)) - Ops.insert(Ops.end(), Add->op_begin(), Add->op_begin()); - else if (!Sum->isZero()) - Ops.push_back(Sum); + Ops = Add->getOperands(); + else { + Ops.clear(); + if (!Sum->isZero()) + Ops.push_back(Sum); + } // Then append the addrecs. Ops.insert(Ops.end(), AddRecs.begin(), AddRecs.end()); } @@ -1054,9 +1060,10 @@ if (CanonicalIV && SE.getTypeSizeInBits(CanonicalIV->getType()) > SE.getTypeSizeInBits(Ty)) { - SmallVector NewOps(S->getNumOperands()); - for (unsigned i = 0, e = S->getNumOperands(); i != e; ++i) - NewOps[i] = SE.getAnyExtendExpr(S->op_begin()[i], CanonicalIV->getType()); + const SmallVectorImpl &Ops = S->getOperands(); + SmallVector NewOps(Ops.size()); + for (unsigned i = 0, e = Ops.size(); i != e; ++i) + NewOps[i] = SE.getAnyExtendExpr(Ops[i], CanonicalIV->getType()); Value *V = expand(SE.getAddRecExpr(NewOps, S->getLoop())); BasicBlock *SaveInsertBB = Builder.GetInsertBlock(); BasicBlock::iterator SaveInsertPt = Builder.GetInsertPoint(); @@ -1071,7 +1078,8 @@ // {X,+,F} --> X + {0,+,F} if (!S->getStart()->isZero()) { - SmallVector NewOps(S->op_begin(), S->op_end()); + const SmallVectorImpl &SOperands = S->getOperands(); + SmallVector NewOps(SOperands.begin(), SOperands.end()); NewOps[0] = SE.getIntegerSCEV(0, Ty); const SCEV *Rest = SE.getAddRecExpr(NewOps, L); From benny.kra at googlemail.com Wed Mar 17 14:55:31 2010 From: benny.kra at googlemail.com (Benjamin Kramer) Date: Wed, 17 Mar 2010 19:55:31 -0000 Subject: [llvm-commits] [llvm] r98763 - /llvm/trunk/lib/Target/PIC16/PIC16Section.h Message-ID: <20100317195531.68AA02A6C12C@llvm.org> Author: d0k Date: Wed Mar 17 14:55:31 2010 New Revision: 98763 URL: http://llvm.org/viewvc/llvm-project?rev=98763&view=rev Log: Initialize Size member to appease valgrind. Modified: llvm/trunk/lib/Target/PIC16/PIC16Section.h Modified: llvm/trunk/lib/Target/PIC16/PIC16Section.h URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Target/PIC16/PIC16Section.h?rev=98763&r1=98762&r2=98763&view=diff ============================================================================== --- llvm/trunk/lib/Target/PIC16/PIC16Section.h (original) +++ llvm/trunk/lib/Target/PIC16/PIC16Section.h Wed Mar 17 14:55:31 2010 @@ -45,7 +45,7 @@ PIC16Section(const StringRef &name, SectionKind K, const std::string &addr, int color) - : MCSection(K), Name(name), Address(addr), Color(color) { + : MCSection(K), Name(name), Address(addr), Color(color), Size(0) { } public: From bob.wilson at apple.com Wed Mar 17 16:13:43 2010 From: bob.wilson at apple.com (Bob Wilson) Date: Wed, 17 Mar 2010 21:13:43 -0000 Subject: [llvm-commits] [llvm] r98768 - /llvm/trunk/lib/Target/ARM/ARMInstrFormats.td Message-ID: <20100317211343.E389B2A6C12C@llvm.org> Author: bwilson Date: Wed Mar 17 16:13:43 2010 New Revision: 98768 URL: http://llvm.org/viewvc/llvm-project?rev=98768&view=rev Log: Increase format field from 5 to 6 bits. ARMII::FormMask was increased to 0x3f in svn r74988 but the format field was never widened. Modified: llvm/trunk/lib/Target/ARM/ARMInstrFormats.td Modified: llvm/trunk/lib/Target/ARM/ARMInstrFormats.td URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Target/ARM/ARMInstrFormats.td?rev=98768&r1=98767&r2=98768&view=diff ============================================================================== --- llvm/trunk/lib/Target/ARM/ARMInstrFormats.td (original) +++ llvm/trunk/lib/Target/ARM/ARMInstrFormats.td Wed Mar 17 16:13:43 2010 @@ -15,8 +15,8 @@ // Format specifies the encoding used by the instruction. This is part of the // ad-hoc solution used to emit machine instruction encodings by our machine // code emitter. -class Format val> { - bits<5> Value = val; +class Format val> { + bits<6> Value = val; } def Pseudo : Format<0>; @@ -183,7 +183,7 @@ bits<2> IndexModeBits = IM.Value; Format F = f; - bits<5> Form = F.Value; + bits<6> Form = F.Value; Domain D = d; bits<2> Dom = D.Value; From bob.wilson at apple.com Wed Mar 17 16:16:45 2010 From: bob.wilson at apple.com (Bob Wilson) Date: Wed, 17 Mar 2010 21:16:45 -0000 Subject: [llvm-commits] [llvm] r98769 - /llvm/trunk/lib/Target/ARM/ARMCodeEmitter.cpp Message-ID: <20100317211645.42AE92A6C12C@llvm.org> Author: bwilson Date: Wed Mar 17 16:16:45 2010 New Revision: 98769 URL: http://llvm.org/viewvc/llvm-project?rev=98769&view=rev Log: Clean up whitespace. Modified: llvm/trunk/lib/Target/ARM/ARMCodeEmitter.cpp Modified: llvm/trunk/lib/Target/ARM/ARMCodeEmitter.cpp URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Target/ARM/ARMCodeEmitter.cpp?rev=98769&r1=98768&r2=98769&view=diff ============================================================================== --- llvm/trunk/lib/Target/ARM/ARMCodeEmitter.cpp (original) +++ llvm/trunk/lib/Target/ARM/ARMCodeEmitter.cpp Wed Mar 17 16:16:45 2010 @@ -55,12 +55,12 @@ const std::vector *MCPEs; const std::vector *MJTEs; bool IsPIC; - + void getAnalysisUsage(AnalysisUsage &AU) const { AU.addRequired(); MachineFunctionPass::getAnalysisUsage(AU); } - + static char ID; public: ARMCodeEmitter(TargetMachine &tm, JITCodeEmitter &mce) @@ -68,7 +68,7 @@ TD(tm.getTargetData()), TM(tm), MCE(mce), MCPEs(0), MJTEs(0), IsPIC(TM.getRelocationModel() == Reloc::PIC_) {} - + /// getBinaryCodeForInstr - This function, generated by the /// CodeEmitterGenerator using TableGen, produces the binary encoding for /// machine instructions. @@ -163,7 +163,7 @@ char ARMCodeEmitter::ID = 0; -/// createARMJITCodeEmitterPass - Return a pass that emits the collected ARM +/// createARMJITCodeEmitterPass - Return a pass that emits the collected ARM /// code to the specified MCE object. FunctionPass *llvm::createARMJITCodeEmitterPass(ARMBaseTargetMachine &TM, JITCodeEmitter &JCE) { @@ -617,8 +617,7 @@ } } -unsigned ARMCodeEmitter::getMachineSoRegOpValue( - const MachineInstr &MI, +unsigned ARMCodeEmitter::getMachineSoRegOpValue(const MachineInstr &MI, const TargetInstrDesc &TID, const MachineOperand &MO, unsigned OpIdx) { @@ -690,7 +689,7 @@ } unsigned ARMCodeEmitter::getAddrModeSBit(const MachineInstr &MI, - const TargetInstrDesc &TID) const { + const TargetInstrDesc &TID) const { for (unsigned i = MI.getNumOperands(), e = TID.getNumOperands(); i != e; --i){ const MachineOperand &MO = MI.getOperand(i-1); if (MO.isReg() && MO.isDef() && MO.getReg() == ARM::CPSR) @@ -699,8 +698,7 @@ return 0; } -void ARMCodeEmitter::emitDataProcessingInstruction( - const MachineInstr &MI, +void ARMCodeEmitter::emitDataProcessingInstruction(const MachineInstr &MI, unsigned ImplicitRd, unsigned ImplicitRn) { const TargetInstrDesc &TID = MI.getDesc(); @@ -765,8 +763,7 @@ emitWordLE(Binary); } -void ARMCodeEmitter::emitLoadStoreInstruction( - const MachineInstr &MI, +void ARMCodeEmitter::emitLoadStoreInstruction(const MachineInstr &MI, unsigned ImplicitRd, unsigned ImplicitRn) { const TargetInstrDesc &TID = MI.getDesc(); @@ -841,7 +838,7 @@ } void ARMCodeEmitter::emitMiscLoadStoreInstruction(const MachineInstr &MI, - unsigned ImplicitRn) { + unsigned ImplicitRn) { const TargetInstrDesc &TID = MI.getDesc(); unsigned Form = TID.TSFlags & ARMII::FormMask; bool IsPrePost = (TID.TSFlags & ARMII::IndexModeMask) != 0; @@ -1238,8 +1235,7 @@ emitWordLE(Binary); } -void ARMCodeEmitter::emitVFPConversionInstruction( - const MachineInstr &MI) { +void ARMCodeEmitter::emitVFPConversionInstruction(const MachineInstr &MI) { const TargetInstrDesc &TID = MI.getDesc(); unsigned Form = TID.TSFlags & ARMII::FormMask; @@ -1329,8 +1325,8 @@ emitWordLE(Binary); } -void ARMCodeEmitter::emitVFPLoadStoreMultipleInstruction( - const MachineInstr &MI) { +void +ARMCodeEmitter::emitVFPLoadStoreMultipleInstruction(const MachineInstr &MI) { const TargetInstrDesc &TID = MI.getDesc(); bool IsUpdating = (TID.TSFlags & ARMII::IndexModeMask) != 0; From grosbach at apple.com Wed Mar 17 16:25:13 2010 From: grosbach at apple.com (Jim Grosbach) Date: Wed, 17 Mar 2010 21:25:13 -0000 Subject: [llvm-commits] [llvm] r98770 - /llvm/trunk/utils/buildit/build_llvm Message-ID: <20100317212514.083E12A6C12C@llvm.org> Author: grosbach Date: Wed Mar 17 16:25:13 2010 New Revision: 98770 URL: http://llvm.org/viewvc/llvm-project?rev=98770&view=rev Log: Use llvm-gcc to build ARM when it's available Modified: llvm/trunk/utils/buildit/build_llvm Modified: llvm/trunk/utils/buildit/build_llvm URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/utils/buildit/build_llvm?rev=98770&r1=98769&r2=98770&view=diff ============================================================================== --- llvm/trunk/utils/buildit/build_llvm (original) +++ llvm/trunk/utils/buildit/build_llvm Wed Mar 17 16:25:13 2010 @@ -106,11 +106,10 @@ # Try to use the platform llvm-gcc. Fall back to gcc if it's not available. for prog in gcc g++ ; do P=$DIR/bin/arm-apple-darwin$DARWIN_VERS-${prog} -# FIXME: Uncomment once llvm-gcc works for this -# T=`xcrun -find llvm-${prog}` -# if [ "x$T" = "x" ] ; then + T=`xcrun -find llvm-${prog}` + if [ "x$T" = "x" ] ; then T=`xcrun -sdk $SDKROOT -find ${prog}` -# fi + fi echo '#!/bin/sh' > $P || exit 1 echo 'exec '$T' -arch armv6 -isysroot '${SDKROOT}' "$@"' >> $P || exit 1 chmod a+x $P || exit 1 From grosbach at apple.com Wed Mar 17 16:28:19 2010 From: grosbach at apple.com (Jim Grosbach) Date: Wed, 17 Mar 2010 21:28:19 -0000 Subject: [llvm-commits] [llvm] r98771 - /llvm/trunk/Makefile.rules Message-ID: <20100317212819.D00BB2A6C12C@llvm.org> Author: grosbach Date: Wed Mar 17 16:28:19 2010 New Revision: 98771 URL: http://llvm.org/viewvc/llvm-project?rev=98771&view=rev Log: remove arm mode workaround for ARM host Modified: llvm/trunk/Makefile.rules Modified: llvm/trunk/Makefile.rules URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/Makefile.rules?rev=98771&r1=98770&r2=98771&view=diff ============================================================================== --- llvm/trunk/Makefile.rules (original) +++ llvm/trunk/Makefile.rules Wed Mar 17 16:28:19 2010 @@ -578,8 +578,6 @@ ifeq ($(TARGET_OS),Darwin) ifneq ($(ARCH),ARM) TargetCommonOpts += -mmacosx-version-min=$(DARWIN_VERSION) - else - TargetCommonOpts += -marm endif endif From scallanan at apple.com Wed Mar 17 17:01:36 2010 From: scallanan at apple.com (Sean Callanan) Date: Wed, 17 Mar 2010 22:01:36 -0000 Subject: [llvm-commits] [llvm] r98773 - /llvm/trunk/tools/edis/Makefile Message-ID: <20100317220136.6D7022A6C12C@llvm.org> Author: spyffe Date: Wed Mar 17 17:01:36 2010 New Revision: 98773 URL: http://llvm.org/viewvc/llvm-project?rev=98773&view=rev Log: Changed install_name for libEnhancedDisassembly.dylib on Mac OS X to match current install location. This has no effect on other platforms. Modified: llvm/trunk/tools/edis/Makefile Modified: llvm/trunk/tools/edis/Makefile URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/tools/edis/Makefile?rev=98773&r1=98772&r2=98773&view=diff ============================================================================== --- llvm/trunk/tools/edis/Makefile (original) +++ llvm/trunk/tools/edis/Makefile Wed Mar 17 17:01:36 2010 @@ -39,11 +39,12 @@ -Wl,-seg1addr -Wl,0xE0000000 # Mac OS X 10.4 and earlier tools do not allow a second -install_name on command line + # Path is /Developer/usr/local/lib for now; will use an rpath-based mechanism soon DARWIN_VERS := $(shell echo $(TARGET_TRIPLE) | sed 's/.*darwin\([0-9]*\).*/\1/') ifneq ($(DARWIN_VERS),8) LLVMLibsOptions := $(LLVMLibsOptions) \ -no-undefined -Wl,-install_name \ - -Wl,"@executable_path/../lib/lib$(LIBRARYNAME)$(SHLIBEXT)" + -Wl,"/Developer/usr/local/lib/lib$(LIBRARYNAME)$(SHLIBEXT)" endif endif From bob.wilson at apple.com Wed Mar 17 17:22:04 2010 From: bob.wilson at apple.com (Bob Wilson) Date: Wed, 17 Mar 2010 15:22:04 -0700 Subject: [llvm-commits] [llvm] r98745 - in /llvm/trunk: lib/Target/ARM/ lib/Target/ARM/AsmPrinter/ test/CodeGen/ARM/ test/CodeGen/Thumb2/ In-Reply-To: <20100317175221.D9A732A6C12C@llvm.org> References: <20100317175221.D9A732A6C12C@llvm.org> Message-ID: On Mar 17, 2010, at 10:52 AM, Johnny Chen wrote: > Author: johnny > Date: Wed Mar 17 12:52:21 2010 > New Revision: 98745 > > URL: http://llvm.org/viewvc/llvm-project?rev=98745&view=rev > Log: > Added sub-formats to the NeonI/NeonXI instructions to further refine the NEONFrm > instructions to help disassembly. > > We also changed the output of the addressing modes to omit the '+' from the > assembler syntax #+/- or +/-. See, for example, A8.6.57/58/60. > > And modified test cases to not expect '+' in +reg or #+num. For example, > > ; CHECK: ldr.w r9, [r7, #28] Some more issues: * The ARMInstPrinter changes should really have been a separate patch. Besides not printing the extra pluses, you made a ton of other changes. I assume these were syncing up with ARMAsmPrinter but I haven't checked that yet. Can you explain? * I don't like the changes to ARMInstrNEON.td. There must be a better way to provide the information you need. Please revert those changes until we work out something more suitable. * There were some other changes mixed in that seem unrelated. See below..... > Modified: llvm/trunk/lib/Target/ARM/AsmPrinter/ARMAsmPrinter.cpp > URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Target/ARM/AsmPrinter/ARMAsmPrinter.cpp?rev=98745&r1=98744&r2=98745&view=diff > ============================================================================== > --- llvm/trunk/lib/Target/ARM/AsmPrinter/ARMAsmPrinter.cpp (original) > +++ llvm/trunk/lib/Target/ARM/AsmPrinter/ARMAsmPrinter.cpp Wed Mar 17 12:52:21 2010 > @@ -612,10 +612,11 @@ > ARMAsmPrinter::printThumbITMask(const MachineInstr *MI, int Op) { > // (3 - the number of trailing zeros) is the number of then / else. > unsigned Mask = MI->getOperand(Op).getImm(); > + unsigned CondBit0 = Mask >> 4 & 1; > unsigned NumTZ = CountTrailingZeros_32(Mask); > assert(NumTZ <= 3 && "Invalid IT mask!"); > for (unsigned Pos = 3, e = NumTZ; Pos > e; --Pos) { > - bool T = (Mask & (1 << Pos)) == 0; > + bool T = ((Mask >> Pos) & 1) == CondBit0; > if (T) > O << 't'; > else What is this for?? > @@ -749,7 +750,18 @@ > if (OffImm < 0) > O << "#-" << -OffImm; > else if (OffImm > 0) > - O << "#+" << OffImm; > + O << "#" << OffImm; > +} > + > +void ARMAsmPrinter::printT2AddrModeImm8s4OffsetOperand(const MachineInstr *MI, > + int OpNum) { > + const MachineOperand &MO1 = MI->getOperand(OpNum); > + int32_t OffImm = (int32_t)MO1.getImm() / 4; > + // Don't print +0. > + if (OffImm < 0) > + O << "#-" << -OffImm * 4; > + else if (OffImm > 0) > + O << "#" << OffImm * 4; > } > > void ARMAsmPrinter::printT2AddrModeSoRegOperand(const MachineInstr *MI, printT2AddrModeImm8s4OffsetOperand used to do nothing. Was that a bug? Why did you add this? From johnny.chen at apple.com Wed Mar 17 17:38:07 2010 From: johnny.chen at apple.com (Johnny Chen) Date: Wed, 17 Mar 2010 15:38:07 -0700 Subject: [llvm-commits] [llvm] r98745 - in /llvm/trunk: lib/Target/ARM/ lib/Target/ARM/AsmPrinter/ test/CodeGen/ARM/ test/CodeGen/Thumb2/ In-Reply-To: References: <20100317175221.D9A732A6C12C@llvm.org> Message-ID: <9EE93BF0-E440-4FC7-B89D-7A8135B1D697@apple.com> The ARMInstPrinter changes are to sync up with the ARMAsmPrinter.cpp changes. I'm currently working on the ARMInstrNEON.td modification to take advantage of the extra bit in Format. Can I keep it as it is for now? The printThumbITMask() thing also sneaked in without the accompanying Thumb2ITBlockPass patch. What would you like me to do? Revert the printThumbITMask() patch for ARMAsmPrinter.cpp as well as ARMInstPrinter, or just the ARMAsmPrinter one? -------------- next part -------------- A non-text attachment was scrubbed... Name: Thumb2ITBlock-patch.diff Type: application/octet-stream Size: 716 bytes Desc: not available Url : http://lists.cs.uiuc.edu/pipermail/llvm-commits/attachments/20100317/5a428b5c/attachment.obj -------------- next part -------------- > printT2AddrModeImm8s4OffsetOperand used to do nothing. Was that a bug? Why did you add this? This is to sync up with the ARMInstPrinter one. It's used by the disassembly, but it could potentially be used by the ARMAsmPrinter. On Mar 17, 2010, at 3:22 PM, Bob Wilson wrote: > On Mar 17, 2010, at 10:52 AM, Johnny Chen wrote: > >> Author: johnny >> Date: Wed Mar 17 12:52:21 2010 >> New Revision: 98745 >> >> URL: http://llvm.org/viewvc/llvm-project?rev=98745&view=rev >> Log: >> Added sub-formats to the NeonI/NeonXI instructions to further refine the NEONFrm >> instructions to help disassembly. >> >> We also changed the output of the addressing modes to omit the '+' from the >> assembler syntax #+/- or +/-. See, for example, A8.6.57/58/60. >> >> And modified test cases to not expect '+' in +reg or #+num. For example, >> >> ; CHECK: ldr.w r9, [r7, #28] > > Some more issues: > > * The ARMInstPrinter changes should really have been a separate patch. Besides not printing the extra pluses, you made a ton of other changes. I assume these were syncing up with ARMAsmPrinter but I haven't checked that yet. Can you explain? > > * I don't like the changes to ARMInstrNEON.td. There must be a better way to provide the information you need. Please revert those changes until we work out something more suitable. > > * There were some other changes mixed in that seem unrelated. See below..... > > >> Modified: llvm/trunk/lib/Target/ARM/AsmPrinter/ARMAsmPrinter.cpp >> URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Target/ARM/AsmPrinter/ARMAsmPrinter.cpp?rev=98745&r1=98744&r2=98745&view=diff >> ============================================================================== >> --- llvm/trunk/lib/Target/ARM/AsmPrinter/ARMAsmPrinter.cpp (original) >> +++ llvm/trunk/lib/Target/ARM/AsmPrinter/ARMAsmPrinter.cpp Wed Mar 17 12:52:21 2010 >> @@ -612,10 +612,11 @@ >> ARMAsmPrinter::printThumbITMask(const MachineInstr *MI, int Op) { >> // (3 - the number of trailing zeros) is the number of then / else. >> unsigned Mask = MI->getOperand(Op).getImm(); >> + unsigned CondBit0 = Mask >> 4 & 1; >> unsigned NumTZ = CountTrailingZeros_32(Mask); >> assert(NumTZ <= 3 && "Invalid IT mask!"); >> for (unsigned Pos = 3, e = NumTZ; Pos > e; --Pos) { >> - bool T = (Mask & (1 << Pos)) == 0; >> + bool T = ((Mask >> Pos) & 1) == CondBit0; >> if (T) >> O << 't'; >> else > > What is this for?? > >> @@ -749,7 +750,18 @@ >> if (OffImm < 0) >> O << "#-" << -OffImm; >> else if (OffImm > 0) >> - O << "#+" << OffImm; >> + O << "#" << OffImm; >> +} >> + >> +void ARMAsmPrinter::printT2AddrModeImm8s4OffsetOperand(const MachineInstr *MI, >> + int OpNum) { >> + const MachineOperand &MO1 = MI->getOperand(OpNum); >> + int32_t OffImm = (int32_t)MO1.getImm() / 4; >> + // Don't print +0. >> + if (OffImm < 0) >> + O << "#-" << -OffImm * 4; >> + else if (OffImm > 0) >> + O << "#" << OffImm * 4; >> } >> >> void ARMAsmPrinter::printT2AddrModeSoRegOperand(const MachineInstr *MI, > > printT2AddrModeImm8s4OffsetOperand used to do nothing. Was that a bug? Why did you add this? > From bob.wilson at apple.com Wed Mar 17 17:42:44 2010 From: bob.wilson at apple.com (Bob Wilson) Date: Wed, 17 Mar 2010 15:42:44 -0700 Subject: [llvm-commits] [llvm] r98745 - in /llvm/trunk: lib/Target/ARM/ lib/Target/ARM/AsmPrinter/ test/CodeGen/ARM/ test/CodeGen/Thumb2/ In-Reply-To: <9EE93BF0-E440-4FC7-B89D-7A8135B1D697@apple.com> References: <20100317175221.D9A732A6C12C@llvm.org> <9EE93BF0-E440-4FC7-B89D-7A8135B1D697@apple.com> Message-ID: Please revert all the changes that were not directly related to removing the "+" from the asm output (except you can keep the ARMInstPrinter changes if you like). It will be too confusing to review subsequent patches if the baseline is left as it is now. Please make sure that future commits have only one logical change per commit. On Mar 17, 2010, at 3:38 PM, Johnny Chen wrote: > The ARMInstPrinter changes are to sync up with the ARMAsmPrinter.cpp changes. > > I'm currently working on the ARMInstrNEON.td modification to take advantage of the extra bit in Format. > Can I keep it as it is for now? > > The printThumbITMask() thing also sneaked in without the accompanying > Thumb2ITBlockPass patch. What would you like me to do? Revert the printThumbITMask() patch > for ARMAsmPrinter.cpp as well as ARMInstPrinter, or just the ARMAsmPrinter one? > > > >> printT2AddrModeImm8s4OffsetOperand used to do nothing. Was that a bug? Why did you add this? > > This is to sync up with the ARMInstPrinter one. It's used by the disassembly, but it could potentially > be used by the ARMAsmPrinter. > > On Mar 17, 2010, at 3:22 PM, Bob Wilson wrote: > >> On Mar 17, 2010, at 10:52 AM, Johnny Chen wrote: >> >>> Author: johnny >>> Date: Wed Mar 17 12:52:21 2010 >>> New Revision: 98745 >>> >>> URL: http://llvm.org/viewvc/llvm-project?rev=98745&view=rev >>> Log: >>> Added sub-formats to the NeonI/NeonXI instructions to further refine the NEONFrm >>> instructions to help disassembly. >>> >>> We also changed the output of the addressing modes to omit the '+' from the >>> assembler syntax #+/- or +/-. See, for example, A8.6.57/58/60. >>> >>> And modified test cases to not expect '+' in +reg or #+num. For example, >>> >>> ; CHECK: ldr.w r9, [r7, #28] >> >> Some more issues: >> >> * The ARMInstPrinter changes should really have been a separate patch. Besides not printing the extra pluses, you made a ton of other changes. I assume these were syncing up with ARMAsmPrinter but I haven't checked that yet. Can you explain? >> >> * I don't like the changes to ARMInstrNEON.td. There must be a better way to provide the information you need. Please revert those changes until we work out something more suitable. >> >> * There were some other changes mixed in that seem unrelated. See below..... >> >> >>> Modified: llvm/trunk/lib/Target/ARM/AsmPrinter/ARMAsmPrinter.cpp >>> URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Target/ARM/AsmPrinter/ARMAsmPrinter.cpp?rev=98745&r1=98744&r2=98745&view=diff >>> ============================================================================== >>> --- llvm/trunk/lib/Target/ARM/AsmPrinter/ARMAsmPrinter.cpp (original) >>> +++ llvm/trunk/lib/Target/ARM/AsmPrinter/ARMAsmPrinter.cpp Wed Mar 17 12:52:21 2010 >>> @@ -612,10 +612,11 @@ >>> ARMAsmPrinter::printThumbITMask(const MachineInstr *MI, int Op) { >>> // (3 - the number of trailing zeros) is the number of then / else. >>> unsigned Mask = MI->getOperand(Op).getImm(); >>> + unsigned CondBit0 = Mask >> 4 & 1; >>> unsigned NumTZ = CountTrailingZeros_32(Mask); >>> assert(NumTZ <= 3 && "Invalid IT mask!"); >>> for (unsigned Pos = 3, e = NumTZ; Pos > e; --Pos) { >>> - bool T = (Mask & (1 << Pos)) == 0; >>> + bool T = ((Mask >> Pos) & 1) == CondBit0; >>> if (T) >>> O << 't'; >>> else >> >> What is this for?? >> >>> @@ -749,7 +750,18 @@ >>> if (OffImm < 0) >>> O << "#-" << -OffImm; >>> else if (OffImm > 0) >>> - O << "#+" << OffImm; >>> + O << "#" << OffImm; >>> +} >>> + >>> +void ARMAsmPrinter::printT2AddrModeImm8s4OffsetOperand(const MachineInstr *MI, >>> + int OpNum) { >>> + const MachineOperand &MO1 = MI->getOperand(OpNum); >>> + int32_t OffImm = (int32_t)MO1.getImm() / 4; >>> + // Don't print +0. >>> + if (OffImm < 0) >>> + O << "#-" << -OffImm * 4; >>> + else if (OffImm > 0) >>> + O << "#" << OffImm * 4; >>> } >>> >>> void ARMAsmPrinter::printT2AddrModeSoRegOperand(const MachineInstr *MI, >> >> printT2AddrModeImm8s4OffsetOperand used to do nothing. Was that a bug? Why did you add this? >> > From johnny.chen at apple.com Wed Mar 17 18:01:59 2010 From: johnny.chen at apple.com (Johnny Chen) Date: Wed, 17 Mar 2010 23:01:59 -0000 Subject: [llvm-commits] [llvm] r98774 - /llvm/trunk/lib/Target/ARM/AsmPrinter/ARMAsmPrinter.cpp Message-ID: <20100317230159.B51492A6C12C@llvm.org> Author: johnny Date: Wed Mar 17 18:01:59 2010 New Revision: 98774 URL: http://llvm.org/viewvc/llvm-project?rev=98774&view=rev Log: Refines 98745 so that it only contains the patch related to the output of the addressing modes to omit the '+' from the assembler syntax #+/- or +/-. This patch removes the impl of printT2AddrModeImm8s4OffsetOperand() from ARMAsmPrinter.cpp. It is used by disassembler as of now. Modified: llvm/trunk/lib/Target/ARM/AsmPrinter/ARMAsmPrinter.cpp Modified: llvm/trunk/lib/Target/ARM/AsmPrinter/ARMAsmPrinter.cpp URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Target/ARM/AsmPrinter/ARMAsmPrinter.cpp?rev=98774&r1=98773&r2=98774&view=diff ============================================================================== --- llvm/trunk/lib/Target/ARM/AsmPrinter/ARMAsmPrinter.cpp (original) +++ llvm/trunk/lib/Target/ARM/AsmPrinter/ARMAsmPrinter.cpp Wed Mar 17 18:01:59 2010 @@ -120,7 +120,7 @@ void printT2AddrModeImm8Operand(const MachineInstr *MI, int OpNum); void printT2AddrModeImm8s4Operand(const MachineInstr *MI, int OpNum); void printT2AddrModeImm8OffsetOperand(const MachineInstr *MI, int OpNum); - void printT2AddrModeImm8s4OffsetOperand(const MachineInstr *MI, int OpNum); + void printT2AddrModeImm8s4OffsetOperand(const MachineInstr *MI, int OpNum) {} void printT2AddrModeSoRegOperand(const MachineInstr *MI, int OpNum); void printCPSOptionOperand(const MachineInstr *MI, int OpNum) {} @@ -753,17 +753,6 @@ O << "#" << OffImm; } -void ARMAsmPrinter::printT2AddrModeImm8s4OffsetOperand(const MachineInstr *MI, - int OpNum) { - const MachineOperand &MO1 = MI->getOperand(OpNum); - int32_t OffImm = (int32_t)MO1.getImm() / 4; - // Don't print +0. - if (OffImm < 0) - O << "#-" << -OffImm * 4; - else if (OffImm > 0) - O << "#" << OffImm * 4; -} - void ARMAsmPrinter::printT2AddrModeSoRegOperand(const MachineInstr *MI, int OpNum) { const MachineOperand &MO1 = MI->getOperand(OpNum); From johnny.chen at apple.com Wed Mar 17 18:14:23 2010 From: johnny.chen at apple.com (Johnny Chen) Date: Wed, 17 Mar 2010 23:14:23 -0000 Subject: [llvm-commits] [llvm] r98775 - /llvm/trunk/lib/Target/ARM/Thumb2ITBlockPass.cpp Message-ID: <20100317231423.5AFB12A6C12C@llvm.org> Author: johnny Date: Wed Mar 17 18:14:23 2010 New Revision: 98775 URL: http://llvm.org/viewvc/llvm-project?rev=98775&view=rev Log: Fixed a bug in the IT mask printing where T means the cond bit in the mask matches that of Firstcond[0] and E means otherwise. The Firstcond[0] is also tagged in the Mask to facilitate Asm printing. The disassembler also depends on this arrangement. This is similar to what's described in A2.5.2 ITSTATE. Ran: utils/lit/lit.py test/CodeGen/ARM test/CodeGen/Thumb test/CodeGen/Thumb2 successfully. Modified: llvm/trunk/lib/Target/ARM/Thumb2ITBlockPass.cpp Modified: llvm/trunk/lib/Target/ARM/Thumb2ITBlockPass.cpp URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Target/ARM/Thumb2ITBlockPass.cpp?rev=98775&r1=98774&r2=98775&view=diff ============================================================================== --- llvm/trunk/lib/Target/ARM/Thumb2ITBlockPass.cpp (original) +++ llvm/trunk/lib/Target/ARM/Thumb2ITBlockPass.cpp Wed Mar 17 18:14:23 2010 @@ -78,14 +78,16 @@ DebugLoc ndl = NMI->getDebugLoc(); unsigned NPredReg = 0; ARMCC::CondCodes NCC = getPredicate(NMI, NPredReg); - if (NCC == OCC) { - Mask |= (1 << Pos); - } else if (NCC != CC) + if (NCC == CC || NCC == OCC) + Mask |= (NCC & 1) << Pos; + else break; --Pos; ++MBBI; } Mask |= (1 << Pos); + // Tag along (firstcond[0] << 4) with the mask. + Mask |= (CC & 1) << 4; MIB.addImm(Mask); Modified = true; ++NumITs; From stoklund at 2pi.dk Wed Mar 17 18:21:59 2010 From: stoklund at 2pi.dk (Jakob Stoklund Olesen) Date: Wed, 17 Mar 2010 23:21:59 -0000 Subject: [llvm-commits] [llvm] r98776 - /llvm/trunk/lib/CodeGen/SimpleRegisterCoalescing.cpp Message-ID: <20100317232159.0B0E62A6C12C@llvm.org> Author: stoklund Date: Wed Mar 17 18:21:58 2010 New Revision: 98776 URL: http://llvm.org/viewvc/llvm-project?rev=98776&view=rev Log: Change coalescer complexity from N^2 to N logN by changing one letter. Remove ugly hack that aborted the coalescer before using N^2 time. This affects functions with very complicated live intervals for physical registers, i.e. functions with thousands of function calls. Modified: llvm/trunk/lib/CodeGen/SimpleRegisterCoalescing.cpp Modified: llvm/trunk/lib/CodeGen/SimpleRegisterCoalescing.cpp URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/CodeGen/SimpleRegisterCoalescing.cpp?rev=98776&r1=98775&r2=98776&view=diff ============================================================================== --- llvm/trunk/lib/CodeGen/SimpleRegisterCoalescing.cpp (original) +++ llvm/trunk/lib/CodeGen/SimpleRegisterCoalescing.cpp Wed Mar 17 18:21:58 2010 @@ -1682,20 +1682,9 @@ // density, do not join them, instead mark the physical register as its // allocation preference. LiveInterval &JoinVInt = SrcIsPhys ? DstInt : SrcInt; - LiveInterval &JoinPInt = SrcIsPhys ? SrcInt : DstInt; unsigned JoinVReg = SrcIsPhys ? DstReg : SrcReg; unsigned JoinPReg = SrcIsPhys ? SrcReg : DstReg; - // Don't join with physregs that have a ridiculous number of live - // ranges. The data structure performance is really bad when that - // happens. - if (JoinPInt.ranges.size() > 1000) { - mri_->setRegAllocationHint(JoinVInt.reg, 0, JoinPReg); - ++numAborts; - DEBUG(dbgs() << "\tPhysical register too complicated, abort!\n"); - return false; - } - const TargetRegisterClass *RC = mri_->getRegClass(JoinVReg); unsigned Threshold = allocatableRCRegs_[RC].count() * 2; unsigned Length = li_->getApproximateInstructionCount(JoinVInt); @@ -2170,7 +2159,7 @@ // Update the liveintervals of sub-registers. if (TargetRegisterInfo::isPhysicalRegister(LHS.reg)) for (const unsigned *AS = tri_->getSubRegisters(LHS.reg); *AS; ++AS) - li_->getOrCreateInterval(*AS).MergeInClobberRanges(*li_, LHS, + li_->getOrCreateInterval(*AS).MergeInClobberRanges(*li_, RHS, li_->getVNInfoAllocator()); return true; From clattner at apple.com Wed Mar 17 18:24:20 2010 From: clattner at apple.com (Chris Lattner) Date: Wed, 17 Mar 2010 16:24:20 -0700 Subject: [llvm-commits] [llvm] r98776 - /llvm/trunk/lib/CodeGen/SimpleRegisterCoalescing.cpp In-Reply-To: <20100317232159.0B0E62A6C12C@llvm.org> References: <20100317232159.0B0E62A6C12C@llvm.org> Message-ID: <054B9458-25B2-4165-9CB9-00F243FEB2EA@apple.com> On Mar 17, 2010, at 4:21 PM, Jakob Stoklund Olesen wrote: > Author: stoklund > Date: Wed Mar 17 18:21:58 2010 > New Revision: 98776 > > URL: http://llvm.org/viewvc/llvm-project?rev=98776&view=rev > Log: > Change coalescer complexity from N^2 to N logN by changing one letter. > > Remove ugly hack that aborted the coalescer before using N^2 time. > > This affects functions with very complicated live intervals for physical > registers, i.e. functions with thousands of function calls. > Nice! From johnny.chen at apple.com Wed Mar 17 18:26:50 2010 From: johnny.chen at apple.com (Johnny Chen) Date: Wed, 17 Mar 2010 23:26:50 -0000 Subject: [llvm-commits] [llvm] r98777 - in /llvm/trunk/lib/Target/ARM: ARMInstrFormats.td ARMInstrNEON.td Message-ID: <20100317232650.6C07A2A6C12C@llvm.org> Author: johnny Date: Wed Mar 17 18:26:50 2010 New Revision: 98777 URL: http://llvm.org/viewvc/llvm-project?rev=98777&view=rev Log: Revert 98745 with respect to the addition of NEONFrm subformats for disassembly. There is a better way coming up. Modified: llvm/trunk/lib/Target/ARM/ARMInstrFormats.td llvm/trunk/lib/Target/ARM/ARMInstrNEON.td Modified: llvm/trunk/lib/Target/ARM/ARMInstrFormats.td URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Target/ARM/ARMInstrFormats.td?rev=98777&r1=98776&r2=98777&view=diff ============================================================================== --- llvm/trunk/lib/Target/ARM/ARMInstrFormats.td (original) +++ llvm/trunk/lib/Target/ARM/ARMInstrFormats.td Wed Mar 17 18:26:50 2010 @@ -1464,29 +1464,6 @@ // ARM NEON Instruction templates. // -// NSFormat specifies further details of a NEON instruction. This is used by -// the disassembler to classify NEONFrm instructions for disassembly purpose. -class NSFormat val> { - bits<5> Value = val; -} -def NSFormatNone : NSFormat<0>; -def VLDSTLaneFrm : NSFormat<1>; -def VLDSTLaneDblFrm : NSFormat<2>; -def VLDSTRQFrm : NSFormat<3>; -def NVdImmFrm : NSFormat<4>; -def NVdVmImmFrm : NSFormat<5>; -def NVdVmImmVCVTFrm : NSFormat<6>; -def NVdVmImmVDupLaneFrm : NSFormat<7>; -def NVdVmImmVSHLLFrm : NSFormat<8>; -def NVectorShuffleFrm : NSFormat<9>; -def NVectorShiftFrm : NSFormat<10>; -def NVectorShift2Frm : NSFormat<11>; -def NVdVnVmImmFrm : NSFormat<12>; -def NVdVnVmImmVectorShiftFrm : NSFormat<13>; -def NVdVnVmImmVectorExtractFrm : NSFormat<14>; -def NVdVnVmImmMulScalarFrm : NSFormat<15>; -def VTBLFrm : NSFormat<16>; - class NeonI pattern> : InstARM { @@ -1497,8 +1474,6 @@ !strconcat("\t", asm)); let Pattern = pattern; list Predicates = [HasNEON]; - NSFormat NSF = NSFormatNone; // For disassembly. - bits<5> NSForm = NSFormatNone.Value; // For disassembly. } // Same as NeonI except it does not have a "data type" specifier. @@ -1510,8 +1485,6 @@ let AsmString = !strconcat(!strconcat(opc, "${p}"), !strconcat("\t", asm)); let Pattern = pattern; list Predicates = [HasNEON]; - NSFormat NSF = NSFormatNone; // For disassembly. - bits<5> NSForm = NSFormatNone.Value; // For disassembly. } class NI pattern> : NeonXI { - let NSF = VLDSTRQFrm; // For disassembly. - let NSForm = VLDSTRQFrm.Value; // For disassembly. } class NLdSt op21_20, bits<4> op11_8, bits<4> op7_4, @@ -1538,8 +1509,6 @@ let Inst{21-20} = op21_20; let Inst{11-8} = op11_8; let Inst{7-4} = op7_4; - let NSF = VLDSTLaneFrm; // For disassembly. - let NSForm = VLDSTLaneFrm.Value; // For disassembly. } class NDataI op7_4, string OpcodeStr, string Dt> : NLdSt<0,0b10,0b1001,op7_4, (outs DPR:$dst1, DPR:$dst2), (ins addrmode6:$addr), IIC_VLD2, - OpcodeStr, Dt, "\\{$dst1, $dst2\\}, $addr", "", []> { - let NSF = VLDSTLaneDblFrm; // For disassembly. - let NSForm = VLDSTLaneDblFrm.Value; // For disassembly. -} + OpcodeStr, Dt, "\\{$dst1, $dst2\\}, $addr", "", []>; def VLD2d8D : VLD2Ddbl<0b0000, "vld2", "8">; def VLD2d16D : VLD2Ddbl<0b0100, "vld2", "16">; @@ -231,10 +228,7 @@ : NLdSt<0,0b10,0b0101,op7_4, (outs DPR:$dst1, DPR:$dst2, DPR:$dst3, GPR:$wb), (ins addrmode6:$addr), IIC_VLD3, OpcodeStr, Dt, "\\{$dst1, $dst2, $dst3\\}, $addr", - "$addr.addr = $wb", []> { - let NSF = VLDSTLaneDblFrm; // For disassembly. - let NSForm = VLDSTLaneDblFrm.Value; // For disassembly. -} + "$addr.addr = $wb", []>; def VLD3d8 : VLD3D<0b0000, "vld3", "8">; def VLD3d16 : VLD3D<0b0100, "vld3", "16">; @@ -266,10 +260,7 @@ (outs DPR:$dst1, DPR:$dst2, DPR:$dst3, DPR:$dst4, GPR:$wb), (ins addrmode6:$addr), IIC_VLD4, OpcodeStr, Dt, "\\{$dst1, $dst2, $dst3, $dst4\\}, $addr", - "$addr.addr = $wb", []> { - let NSF = VLDSTLaneDblFrm; // For disassembly. - let NSForm = VLDSTLaneDblFrm.Value; // For disassembly. -} + "$addr.addr = $wb", []>; def VLD4d8 : VLD4D<0b0000, "vld4", "8">; def VLD4d16 : VLD4D<0b0100, "vld4", "16">; @@ -306,28 +297,12 @@ def VLD2LNd32 : VLD2LN<0b1001, "vld2", "32"> { let Inst{6} = 0; } // vld2 to double-spaced even registers. -def VLD2LNq16a: VLD2LN<0b0101, "vld2", "16"> { - let Inst{5} = 1; - let NSF = VLDSTLaneDblFrm; // For disassembly. - let NSForm = VLDSTLaneDblFrm.Value; // For disassembly. -} -def VLD2LNq32a: VLD2LN<0b1001, "vld2", "32"> { - let Inst{6} = 1; - let NSF = VLDSTLaneDblFrm; // For disassembly. - let NSForm = VLDSTLaneDblFrm.Value; // For disassembly. -} +def VLD2LNq16a: VLD2LN<0b0101, "vld2", "16"> { let Inst{5} = 1; } +def VLD2LNq32a: VLD2LN<0b1001, "vld2", "32"> { let Inst{6} = 1; } // vld2 to double-spaced odd registers. -def VLD2LNq16b: VLD2LN<0b0101, "vld2", "16"> { - let Inst{5} = 1; - let NSF = VLDSTLaneDblFrm; // For disassembly. - let NSForm = VLDSTLaneDblFrm.Value; // For disassembly. -} -def VLD2LNq32b: VLD2LN<0b1001, "vld2", "32"> { - let Inst{6} = 1; - let NSF = VLDSTLaneDblFrm; // For disassembly. - let NSForm = VLDSTLaneDblFrm.Value; // For disassembly. -} +def VLD2LNq16b: VLD2LN<0b0101, "vld2", "16"> { let Inst{5} = 1; } +def VLD2LNq32b: VLD2LN<0b1001, "vld2", "32"> { let Inst{6} = 1; } // VLD3LN : Vector Load (single 3-element structure to one lane) class VLD3LN op11_8, string OpcodeStr, string Dt> @@ -343,11 +318,7 @@ def VLD3LNd32 : VLD3LN<0b1010, "vld3", "32"> { let Inst{6-4} = 0b000; } // vld3 to double-spaced even registers. -def VLD3LNq16a: VLD3LN<0b0110, "vld3", "16"> { - let Inst{5-4} = 0b10; - let NSF = VLDSTLaneDblFrm; // For disassembly. - let NSForm = VLDSTLaneDblFrm.Value; // For disassembly. -} +def VLD3LNq16a: VLD3LN<0b0110, "vld3", "16"> { let Inst{5-4} = 0b10; } def VLD3LNq32a: VLD3LN<0b1010, "vld3", "32"> { let Inst{6-4} = 0b100; } // vld3 to double-spaced odd registers. @@ -369,28 +340,12 @@ def VLD4LNd32 : VLD4LN<0b1011, "vld4", "32"> { let Inst{6} = 0; } // vld4 to double-spaced even registers. -def VLD4LNq16a: VLD4LN<0b0111, "vld4", "16"> { - let Inst{5} = 1; - let NSF = VLDSTLaneDblFrm; // For disassembly. - let NSForm = VLDSTLaneDblFrm.Value; // For disassembly. -} -def VLD4LNq32a: VLD4LN<0b1011, "vld4", "32"> { - let Inst{6} = 1; - let NSF = VLDSTLaneDblFrm; // For disassembly. - let NSForm = VLDSTLaneDblFrm.Value; // For disassembly. -} +def VLD4LNq16a: VLD4LN<0b0111, "vld4", "16"> { let Inst{5} = 1; } +def VLD4LNq32a: VLD4LN<0b1011, "vld4", "32"> { let Inst{6} = 1; } // vld4 to double-spaced odd registers. -def VLD4LNq16b: VLD4LN<0b0111, "vld4", "16"> { - let Inst{5} = 1; - let NSF = VLDSTLaneDblFrm; // For disassembly. - let NSForm = VLDSTLaneDblFrm.Value; // For disassembly. -} -def VLD4LNq32b: VLD4LN<0b1011, "vld4", "32"> { - let Inst{6} = 1; - let NSF = VLDSTLaneDblFrm; // For disassembly. - let NSForm = VLDSTLaneDblFrm.Value; // For disassembly. -} +def VLD4LNq16b: VLD4LN<0b0111, "vld4", "16"> { let Inst{5} = 1; } +def VLD4LNq32b: VLD4LN<0b1011, "vld4", "32"> { let Inst{6} = 1; } // VLD1DUP : Vector Load (single element to all lanes) // VLD2DUP : Vector Load (single 2-element structure to all lanes) @@ -478,10 +433,7 @@ class VST2Ddbl op7_4, string OpcodeStr, string Dt> : NLdSt<0, 0b00, 0b1001, op7_4, (outs), (ins addrmode6:$addr, DPR:$src1, DPR:$src2), IIC_VST, - OpcodeStr, Dt, "\\{$src1, $src2\\}, $addr", "", []> { - let NSF = VLDSTLaneDblFrm; // For disassembly. - let NSForm = VLDSTLaneDblFrm.Value; // For disassembly. -} + OpcodeStr, Dt, "\\{$src1, $src2\\}, $addr", "", []>; def VST2d8D : VST2Ddbl<0b0000, "vst2", "8">; def VST2d16D : VST2Ddbl<0b0100, "vst2", "16">; @@ -496,10 +448,7 @@ : NLdSt<0,0b00,0b0101,op7_4, (outs GPR:$wb), (ins addrmode6:$addr, DPR:$src1, DPR:$src2, DPR:$src3), IIC_VST, OpcodeStr, Dt, "\\{$src1, $src2, $src3\\}, $addr", - "$addr.addr = $wb", []> { - let NSF = VLDSTLaneDblFrm; // For disassembly. - let NSForm = VLDSTLaneDblFrm.Value; // For disassembly. -} + "$addr.addr = $wb", []>; def VST3d8 : VST3D<0b0000, "vst3", "8">; def VST3d16 : VST3D<0b0100, "vst3", "16">; @@ -529,10 +478,7 @@ : NLdSt<0,0b00,0b0001,op7_4, (outs GPR:$wb), (ins addrmode6:$addr, DPR:$src1, DPR:$src2, DPR:$src3, DPR:$src4), IIC_VST, OpcodeStr, Dt, "\\{$src1, $src2, $src3, $src4\\}, $addr", - "$addr.addr = $wb", []> { - let NSF = VLDSTLaneDblFrm; // For disassembly. - let NSForm = VLDSTLaneDblFrm.Value; // For disassembly. -} + "$addr.addr = $wb", []>; def VST4d8 : VST4D<0b0000, "vst4", "8">; def VST4d16 : VST4D<0b0100, "vst4", "16">; @@ -569,28 +515,12 @@ def VST2LNd32 : VST2LN<0b1001, "vst2", "32"> { let Inst{6} = 0; } // vst2 to double-spaced even registers. -def VST2LNq16a: VST2LN<0b0101, "vst2", "16"> { - let Inst{5} = 1; - let NSF = VLDSTLaneDblFrm; // For disassembly. - let NSForm = VLDSTLaneDblFrm.Value; // For disassembly. -} -def VST2LNq32a: VST2LN<0b1001, "vst2", "32"> { - let Inst{6} = 1; - let NSF = VLDSTLaneDblFrm; // For disassembly. - let NSForm = VLDSTLaneDblFrm.Value; // For disassembly. -} +def VST2LNq16a: VST2LN<0b0101, "vst2", "16"> { let Inst{5} = 1; } +def VST2LNq32a: VST2LN<0b1001, "vst2", "32"> { let Inst{6} = 1; } // vst2 to double-spaced odd registers. -def VST2LNq16b: VST2LN<0b0101, "vst2", "16"> { - let Inst{5} = 1; - let NSF = VLDSTLaneDblFrm; // For disassembly. - let NSForm = VLDSTLaneDblFrm.Value; // For disassembly. -} -def VST2LNq32b: VST2LN<0b1001, "vst2", "32"> { - let Inst{6} = 1; - let NSF = VLDSTLaneDblFrm; // For disassembly. - let NSForm = VLDSTLaneDblFrm.Value; // For disassembly. -} +def VST2LNq16b: VST2LN<0b0101, "vst2", "16"> { let Inst{5} = 1; } +def VST2LNq32b: VST2LN<0b1001, "vst2", "32"> { let Inst{6} = 1; } // VST3LN : Vector Store (single 3-element structure from one lane) class VST3LN op11_8, string OpcodeStr, string Dt> @@ -605,28 +535,12 @@ def VST3LNd32 : VST3LN<0b1010, "vst3", "32"> { let Inst{6-4} = 0b000; } // vst3 to double-spaced even registers. -def VST3LNq16a: VST3LN<0b0110, "vst3", "16"> { - let Inst{5-4} = 0b10; - let NSF = VLDSTLaneDblFrm; // For disassembly. - let NSForm = VLDSTLaneDblFrm.Value; // For disassembly. -} -def VST3LNq32a: VST3LN<0b1010, "vst3", "32"> { - let Inst{6-4} = 0b100; - let NSF = VLDSTLaneDblFrm; // For disassembly. - let NSForm = VLDSTLaneDblFrm.Value; // For disassembly. -} +def VST3LNq16a: VST3LN<0b0110, "vst3", "16"> { let Inst{5-4} = 0b10; } +def VST3LNq32a: VST3LN<0b1010, "vst3", "32"> { let Inst{6-4} = 0b100; } // vst3 to double-spaced odd registers. -def VST3LNq16b: VST3LN<0b0110, "vst3", "16"> { - let Inst{5-4} = 0b10; - let NSF = VLDSTLaneDblFrm; // For disassembly. - let NSForm = VLDSTLaneDblFrm.Value; // For disassembly. -} -def VST3LNq32b: VST3LN<0b1010, "vst3", "32"> { - let Inst{6-4} = 0b100; - let NSF = VLDSTLaneDblFrm; // For disassembly. - let NSForm = VLDSTLaneDblFrm.Value; // For disassembly. -} +def VST3LNq16b: VST3LN<0b0110, "vst3", "16"> { let Inst{5-4} = 0b10; } +def VST3LNq32b: VST3LN<0b1010, "vst3", "32"> { let Inst{6-4} = 0b100; } // VST4LN : Vector Store (single 4-element structure from one lane) class VST4LN op11_8, string OpcodeStr, string Dt> @@ -642,28 +556,12 @@ def VST4LNd32 : VST4LN<0b1011, "vst4", "32"> { let Inst{6} = 0; } // vst4 to double-spaced even registers. -def VST4LNq16a: VST4LN<0b0111, "vst4", "16"> { - let Inst{5} = 1; - let NSF = VLDSTLaneDblFrm; // For disassembly. - let NSForm = VLDSTLaneDblFrm.Value; // For disassembly. -} -def VST4LNq32a: VST4LN<0b1011, "vst4", "32"> { - let Inst{6} = 1; - let NSF = VLDSTLaneDblFrm; // For disassembly. - let NSForm = VLDSTLaneDblFrm.Value; // For disassembly. -} +def VST4LNq16a: VST4LN<0b0111, "vst4", "16"> { let Inst{5} = 1; } +def VST4LNq32a: VST4LN<0b1011, "vst4", "32"> { let Inst{6} = 1; } // vst4 to double-spaced odd registers. -def VST4LNq16b: VST4LN<0b0111, "vst4", "16"> { - let Inst{5} = 1; - let NSF = VLDSTLaneDblFrm; // For disassembly. - let NSForm = VLDSTLaneDblFrm.Value; // For disassembly. -} -def VST4LNq32b: VST4LN<0b1011, "vst4", "32"> { - let Inst{6} = 1; - let NSF = VLDSTLaneDblFrm; // For disassembly. - let NSForm = VLDSTLaneDblFrm.Value; // For disassembly. -} +def VST4LNq16b: VST4LN<0b0111, "vst4", "16"> { let Inst{5} = 1; } +def VST4LNq32b: VST4LN<0b1011, "vst4", "32"> { let Inst{6} = 1; } } // mayStore = 1, hasExtraSrcRegAllocReq = 1 @@ -770,18 +668,12 @@ : N2V<0b11, 0b11, op19_18, 0b10, op11_7, 0, 0, (outs DPR:$dst1, DPR:$dst2), (ins DPR:$src1, DPR:$src2), IIC_VPERMD, OpcodeStr, Dt, "$dst1, $dst2", - "$src1 = $dst1, $src2 = $dst2", []> { - let NSF = NVectorShuffleFrm; // For disassembly. - let NSForm = NVectorShuffleFrm.Value; // For disassembly. -} + "$src1 = $dst1, $src2 = $dst2", []>; class N2VQShuffle op19_18, bits<5> op11_7, InstrItinClass itin, string OpcodeStr, string Dt> : N2V<0b11, 0b11, op19_18, 0b10, op11_7, 1, 0, (outs QPR:$dst1, QPR:$dst2), (ins QPR:$src1, QPR:$src2), itin, OpcodeStr, Dt, "$dst1, $dst2", - "$src1 = $dst1, $src2 = $dst2", []> { - let NSF = NVectorShuffleFrm; // For disassembly. - let NSForm = NVectorShuffleFrm.Value; // For disassembly. -} + "$src1 = $dst1, $src2 = $dst2", []>; // Basic 3-register operations: single-, double- and quad-register. class N3VS op21_20, bits<4> op11_8, bit op4, @@ -823,8 +715,6 @@ (Ty (ShOp (Ty DPR:$src1), (Ty (NEONvduplane (Ty DPR_VFP2:$src2), imm:$lane)))))]>{ let isCommutable = 0; - let NSF = NVdVnVmImmMulScalarFrm; // For disassembly. - let NSForm = NVdVnVmImmMulScalarFrm.Value; // For disassembly. } class N3VDSL16 op21_20, bits<4> op11_8, string OpcodeStr, string Dt, ValueType Ty, SDNode ShOp> @@ -835,8 +725,6 @@ (Ty (ShOp (Ty DPR:$src1), (Ty (NEONvduplane (Ty DPR_8:$src2), imm:$lane)))))]> { let isCommutable = 0; - let NSF = NVdVnVmImmMulScalarFrm; // For disassembly. - let NSForm = NVdVnVmImmMulScalarFrm.Value; // For disassembly. } class N3VQ op21_20, bits<4> op11_8, bit op4, @@ -868,8 +756,6 @@ (ResTy (NEONvduplane (OpTy DPR_VFP2:$src2), imm:$lane)))))]> { let isCommutable = 0; - let NSF = NVdVnVmImmMulScalarFrm; // For disassembly. - let NSForm = NVdVnVmImmMulScalarFrm.Value; // For disassembly. } class N3VQSL16 op21_20, bits<4> op11_8, string OpcodeStr, string Dt, ValueType ResTy, ValueType OpTy, SDNode ShOp> @@ -881,8 +767,6 @@ (ResTy (NEONvduplane (OpTy DPR_8:$src2), imm:$lane)))))]> { let isCommutable = 0; - let NSF = NVdVnVmImmMulScalarFrm; // For disassembly. - let NSForm = NVdVnVmImmMulScalarFrm.Value; // For disassembly. } // Basic 3-register intrinsics, both double- and quad-register. @@ -905,8 +789,6 @@ (Ty (NEONvduplane (Ty DPR_VFP2:$src2), imm:$lane)))))]> { let isCommutable = 0; - let NSF = NVdVnVmImmMulScalarFrm; // For disassembly. - let NSForm = NVdVnVmImmMulScalarFrm.Value; // For disassembly. } class N3VDIntSL16 op21_20, bits<4> op11_8, InstrItinClass itin, string OpcodeStr, string Dt, ValueType Ty, Intrinsic IntOp> @@ -918,8 +800,6 @@ (Ty (NEONvduplane (Ty DPR_8:$src2), imm:$lane)))))]> { let isCommutable = 0; - let NSF = NVdVnVmImmMulScalarFrm; // For disassembly. - let NSForm = NVdVnVmImmMulScalarFrm.Value; // For disassembly. } class N3VQInt op21_20, bits<4> op11_8, bit op4, @@ -942,8 +822,6 @@ (ResTy (NEONvduplane (OpTy DPR_VFP2:$src2), imm:$lane)))))]> { let isCommutable = 0; - let NSF = NVdVnVmImmMulScalarFrm; // For disassembly. - let NSForm = NVdVnVmImmMulScalarFrm.Value; // For disassembly. } class N3VQIntSL16 op21_20, bits<4> op11_8, InstrItinClass itin, string OpcodeStr, string Dt, @@ -956,8 +834,6 @@ (ResTy (NEONvduplane (OpTy DPR_8:$src2), imm:$lane)))))]> { let isCommutable = 0; - let NSF = NVdVnVmImmMulScalarFrm; // For disassembly. - let NSForm = NVdVnVmImmMulScalarFrm.Value; // For disassembly. } // Multiply-Add/Sub operations: single-, double- and quad-register. @@ -988,10 +864,7 @@ (Ty (ShOp (Ty DPR:$src1), (Ty (MulOp DPR:$src2, (Ty (NEONvduplane (Ty DPR_VFP2:$src3), - imm:$lane)))))))]> { - let NSF = NVdVnVmImmMulScalarFrm; // For disassembly. - let NSForm = NVdVnVmImmMulScalarFrm.Value; // For disassembly. -} + imm:$lane)))))))]>; class N3VDMulOpSL16 op21_20, bits<4> op11_8, InstrItinClass itin, string OpcodeStr, string Dt, ValueType Ty, SDNode MulOp, SDNode ShOp> @@ -1003,10 +876,7 @@ (Ty (ShOp (Ty DPR:$src1), (Ty (MulOp DPR:$src2, (Ty (NEONvduplane (Ty DPR_8:$src3), - imm:$lane)))))))]> { - let NSF = NVdVnVmImmMulScalarFrm; // For disassembly. - let NSForm = NVdVnVmImmMulScalarFrm.Value; // For disassembly. -} + imm:$lane)))))))]>; class N3VQMulOp op21_20, bits<4> op11_8, bit op4, InstrItinClass itin, string OpcodeStr, string Dt, ValueType Ty, @@ -1027,10 +897,7 @@ (ResTy (ShOp (ResTy QPR:$src1), (ResTy (MulOp QPR:$src2, (ResTy (NEONvduplane (OpTy DPR_VFP2:$src3), - imm:$lane)))))))]> { - let NSF = NVdVnVmImmMulScalarFrm; // For disassembly. - let NSForm = NVdVnVmImmMulScalarFrm.Value; // For disassembly. -} + imm:$lane)))))))]>; class N3VQMulOpSL16 op21_20, bits<4> op11_8, InstrItinClass itin, string OpcodeStr, string Dt, ValueType ResTy, ValueType OpTy, @@ -1043,10 +910,7 @@ (ResTy (ShOp (ResTy QPR:$src1), (ResTy (MulOp QPR:$src2, (ResTy (NEONvduplane (OpTy DPR_8:$src3), - imm:$lane)))))))]> { - let NSF = NVdVnVmImmMulScalarFrm; // For disassembly. - let NSForm = NVdVnVmImmMulScalarFrm.Value; // For disassembly. -} + imm:$lane)))))))]>; // Neon 3-argument intrinsics, both double- and quad-register. // The destination register is also used as the first source operand register. @@ -1132,10 +996,7 @@ [(set (ResTy QPR:$dst), (ResTy (IntOp (OpTy DPR:$src1), (OpTy (NEONvduplane (OpTy DPR_VFP2:$src2), - imm:$lane)))))]> { - let NSF = NVdVnVmImmMulScalarFrm; // For disassembly. - let NSForm = NVdVnVmImmMulScalarFrm.Value; // For disassembly. -} + imm:$lane)))))]>; class N3VLIntSL16 op21_20, bits<4> op11_8, InstrItinClass itin, string OpcodeStr, string Dt, ValueType ResTy, ValueType OpTy, Intrinsic IntOp> @@ -1145,10 +1006,7 @@ [(set (ResTy QPR:$dst), (ResTy (IntOp (OpTy DPR:$src1), (OpTy (NEONvduplane (OpTy DPR_8:$src2), - imm:$lane)))))]> { - let NSF = NVdVnVmImmMulScalarFrm; // For disassembly. - let NSForm = NVdVnVmImmMulScalarFrm.Value; // For disassembly. -} + imm:$lane)))))]>; // Wide 3-register intrinsics. class N3VWInt op21_20, bits<4> op11_8, bit op4, @@ -1197,10 +1055,6 @@ OpcodeStr, Dt, "$dst, $src2", "$src1 = $dst", [(set QPR:$dst, (ResTy (IntOp (ResTy QPR:$src1), (OpTy QPR:$src2))))]>; -// This is a big let * in block to mark these instructions NVectorShiftFrm to -// help the disassembler. -let NSF = NVectorShiftFrm, NSForm = NVectorShiftFrm.Value in { - // Shift by immediate, // both double- and quad-register. class N2VDSh op11_8, bit op7, bit op4, @@ -1218,6 +1072,16 @@ OpcodeStr, Dt, "$dst, $src, $SIMM", "", [(set QPR:$dst, (Ty (OpNode (Ty QPR:$src), (i32 imm:$SIMM))))]>; +// Long shift by immediate. +class N2VLSh op11_8, bit op7, bit op6, bit op4, + string OpcodeStr, string Dt, + ValueType ResTy, ValueType OpTy, SDNode OpNode> + : N2VImm; + // Narrow shift by immediate. class N2VNSh op11_8, bit op7, bit op6, bit op4, InstrItinClass itin, string OpcodeStr, string Dt, @@ -1260,26 +1124,8 @@ OpcodeStr, Dt, "$dst, $src2, $SIMM", "$src1 = $dst", [(set QPR:$dst, (Ty (ShOp QPR:$src1, QPR:$src2, (i32 imm:$SIMM))))]>; -} // End of "let NSF = NVectorShiftFrm, ..." - -// Long shift by immediate. -class N2VLSh op11_8, bit op7, bit op6, bit op4, - string OpcodeStr, string Dt, - ValueType ResTy, ValueType OpTy, SDNode OpNode> - : N2VImm { - // This has a different interpretation of the shift amount encoding than - // NVectorShiftFrm. - let NSF = NVectorShift2Frm; // For disassembly. - let NSForm = NVectorShift2Frm.Value; // For disassembly. -} - // Convert, with fractional bits immediate, // both double- and quad-register. -let NSF = NVdVmImmVCVTFrm, NSForm = NVdVmImmVCVTFrm.Value in { class N2VCvtD op11_8, bit op7, bit op4, string OpcodeStr, string Dt, ValueType ResTy, ValueType OpTy, Intrinsic IntOp> @@ -1294,7 +1140,6 @@ (outs QPR:$dst), (ins QPR:$src, i32imm:$SIMM), IIC_VUNAQ, OpcodeStr, Dt, "$dst, $src, $SIMM", "", [(set QPR:$dst, (ResTy (IntOp (OpTy QPR:$src), (i32 imm:$SIMM))))]>; -} //===----------------------------------------------------------------------===// // Multiclasses @@ -1505,60 +1350,6 @@ v2i64, v2i64, IntOp, Commutable>; } -// Same as N3VInt_QHSD, except they're for Vector Shift (Register) Instructions. -// D:Vd M:Vm N:Vn (notice that M:Vm is the first operand) -// This helps the disassembler. -let NSF = NVdVnVmImmVectorShiftFrm, NSForm = NVdVnVmImmVectorShiftFrm.Value in { -multiclass N3VInt_HS2 op11_8, bit op4, - InstrItinClass itinD16, InstrItinClass itinD32, - InstrItinClass itinQ16, InstrItinClass itinQ32, - string OpcodeStr, string Dt, - Intrinsic IntOp, bit Commutable = 0> { - // 64-bit vector types. - def v4i16 : N3VDInt; - def v2i32 : N3VDInt; - - // 128-bit vector types. - def v8i16 : N3VQInt; - def v4i32 : N3VQInt; -} -multiclass N3VInt_QHS2 op11_8, bit op4, - InstrItinClass itinD16, InstrItinClass itinD32, - InstrItinClass itinQ16, InstrItinClass itinQ32, - string OpcodeStr, string Dt, - Intrinsic IntOp, bit Commutable = 0> - : N3VInt_HS2 { - def v8i8 : N3VDInt; - def v16i8 : N3VQInt; -} -multiclass N3VInt_QHSD2 op11_8, bit op4, - InstrItinClass itinD16, InstrItinClass itinD32, - InstrItinClass itinQ16, InstrItinClass itinQ32, - string OpcodeStr, string Dt, - Intrinsic IntOp, bit Commutable = 0> - : N3VInt_QHS2 { - def v1i64 : N3VDInt; - def v2i64 : N3VQInt; -} -} // Neon Narrowing 3-register vector intrinsics, // source operand element sizes of 16, 32 and 64 bits: @@ -1828,47 +1619,6 @@ // imm6 = xxxxxx } -// Same as N2VSh_QHSD, except the instructions have a differnt interpretation of -// the shift amount. This helps the disassembler. -let NSF = NVectorShift2Frm, NSForm = NVectorShift2Frm.Value in { -multiclass N2VSh_QHSD2 op11_8, bit op4, - InstrItinClass itin, string OpcodeStr, string Dt, - SDNode OpNode> { - // 64-bit vector types. - def v8i8 : N2VDSh { - let Inst{21-19} = 0b001; // imm6 = 001xxx - } - def v4i16 : N2VDSh { - let Inst{21-20} = 0b01; // imm6 = 01xxxx - } - def v2i32 : N2VDSh { - let Inst{21} = 0b1; // imm6 = 1xxxxx - } - def v1i64 : N2VDSh; - // imm6 = xxxxxx - - // 128-bit vector types. - def v16i8 : N2VQSh { - let Inst{21-19} = 0b001; // imm6 = 001xxx - } - def v8i16 : N2VQSh { - let Inst{21-20} = 0b01; // imm6 = 01xxxx - } - def v4i32 : N2VQSh { - let Inst{21} = 0b1; // imm6 = 1xxxxx - } - def v2i64 : N2VQSh; - // imm6 = xxxxxx -} -} // Neon Shift-Accumulate vector operations, // element sizes of 8, 16, 32 and 64 bits: @@ -1949,47 +1699,6 @@ // imm6 = xxxxxx } -// Same as N2VShIns_QHSD, except the instructions have a differnt interpretation -// of the shift amount. This helps the disassembler. -let NSF = NVectorShift2Frm, NSForm = NVectorShift2Frm.Value in { -multiclass N2VShIns_QHSD2 op11_8, bit op4, - string OpcodeStr, SDNode ShOp> { - // 64-bit vector types. - def v8i8 : N2VDShIns { - let Inst{21-19} = 0b001; // imm6 = 001xxx - } - def v4i16 : N2VDShIns { - let Inst{21-20} = 0b01; // imm6 = 01xxxx - } - def v2i32 : N2VDShIns { - let Inst{21} = 0b1; // imm6 = 1xxxxx - } - def v1i64 : N2VDShIns; - // imm6 = xxxxxx - - // 128-bit vector types. - def v16i8 : N2VQShIns { - let Inst{21-19} = 0b001; // imm6 = 001xxx - } - def v8i16 : N2VQShIns { - let Inst{21-20} = 0b01; // imm6 = 01xxxx - } - def v4i32 : N2VQShIns { - let Inst{21} = 0b1; // imm6 = 1xxxxx - } - def v2i64 : N2VQShIns; - // imm6 = xxxxxx -} -} - // Neon Shift Long operations, // element sizes of 8, 16, 32 bits: multiclass N2VLSh_QHS op11_8, bit op7, bit op6, @@ -2620,21 +2329,18 @@ // Vector Shifts. // VSHL : Vector Shift -defm VSHLs : N3VInt_QHSD2<0,0, 0b0100, 0, IIC_VSHLiD, IIC_VSHLiD, IIC_VSHLiQ, - IIC_VSHLiQ, "vshl", "s", int_arm_neon_vshifts, 0>; -defm VSHLu : N3VInt_QHSD2<1,0, 0b0100, 0, IIC_VSHLiD, IIC_VSHLiD, IIC_VSHLiQ, - IIC_VSHLiQ, "vshl", "u", int_arm_neon_vshiftu, 0>; +defm VSHLs : N3VInt_QHSD<0, 0, 0b0100, 0, IIC_VSHLiD, IIC_VSHLiD, IIC_VSHLiQ, + IIC_VSHLiQ, "vshl", "s", int_arm_neon_vshifts, 0>; +defm VSHLu : N3VInt_QHSD<1, 0, 0b0100, 0, IIC_VSHLiD, IIC_VSHLiD, IIC_VSHLiQ, + IIC_VSHLiQ, "vshl", "u", int_arm_neon_vshiftu, 0>; // VSHL : Vector Shift Left (Immediate) -// (disassembly note: this has a different interpretation of the shift amont) -defm VSHLi : N2VSh_QHSD2<0, 1, 0b0101, 1, IIC_VSHLiD, "vshl", "i", NEONvshl>; +defm VSHLi : N2VSh_QHSD<0, 1, 0b0101, 1, IIC_VSHLiD, "vshl", "i", NEONvshl>; // VSHR : Vector Shift Right (Immediate) defm VSHRs : N2VSh_QHSD<0, 1, 0b0000, 1, IIC_VSHLiD, "vshr", "s", NEONvshrs>; defm VSHRu : N2VSh_QHSD<1, 1, 0b0000, 1, IIC_VSHLiD, "vshr", "u", NEONvshru>; // VSHLL : Vector Shift Left Long -// (disassembly note: this has a different interpretation of the shift amont) defm VSHLLs : N2VLSh_QHS<0, 1, 0b1010, 0, 0, 1, "vshll", "s", NEONvshlls>; -// (disassembly note: this has a different interpretation of the shift amont) defm VSHLLu : N2VLSh_QHS<1, 1, 0b1010, 0, 0, 1, "vshll", "u", NEONvshllu>; // VSHLL : Vector Shift Left Long (with maximum shift count) @@ -2644,8 +2350,6 @@ : N2VLSh { let Inst{21-16} = op21_16; - let NSF = NVdVmImmVSHLLFrm; // For disassembly. - let NSForm = NVdVmImmVSHLLFrm.Value; // For disassembly. } def VSHLLi8 : N2VLShMax<1, 1, 0b110010, 0b0011, 0, 0, 0, "vshll", "i8", v8i16, v8i8, NEONvshlli>; @@ -2659,10 +2363,10 @@ NEONvshrn>; // VRSHL : Vector Rounding Shift -defm VRSHLs : N3VInt_QHSD2<0,0,0b0101,0,IIC_VSHLi4D, IIC_VSHLi4D, IIC_VSHLi4Q, - IIC_VSHLi4Q,"vrshl", "s", int_arm_neon_vrshifts,0>; -defm VRSHLu : N3VInt_QHSD2<1,0,0b0101,0,IIC_VSHLi4D, IIC_VSHLi4D, IIC_VSHLi4Q, - IIC_VSHLi4Q,"vrshl", "u", int_arm_neon_vrshiftu,0>; +defm VRSHLs : N3VInt_QHSD<0,0,0b0101,0, IIC_VSHLi4D, IIC_VSHLi4D, IIC_VSHLi4Q, + IIC_VSHLi4Q, "vrshl", "s", int_arm_neon_vrshifts,0>; +defm VRSHLu : N3VInt_QHSD<1,0,0b0101,0, IIC_VSHLi4D, IIC_VSHLi4D, IIC_VSHLi4Q, + IIC_VSHLi4Q, "vrshl", "u", int_arm_neon_vrshiftu,0>; // VRSHR : Vector Rounding Shift Right defm VRSHRs : N2VSh_QHSD<0,1,0b0010,1, IIC_VSHLi4D, "vrshr", "s", NEONvrshrs>; defm VRSHRu : N2VSh_QHSD<1,1,0b0010,1, IIC_VSHLi4D, "vrshr", "u", NEONvrshru>; @@ -2672,18 +2376,15 @@ NEONvrshrn>; // VQSHL : Vector Saturating Shift -defm VQSHLs : N3VInt_QHSD2<0,0,0b0100,1,IIC_VSHLi4D, IIC_VSHLi4D, IIC_VSHLi4Q, - IIC_VSHLi4Q, "vqshl", "s", int_arm_neon_vqshifts,0>; -defm VQSHLu : N3VInt_QHSD2<1,0,0b0100,1,IIC_VSHLi4D, IIC_VSHLi4D, IIC_VSHLi4Q, - IIC_VSHLi4Q, "vqshl", "u", int_arm_neon_vqshiftu,0>; +defm VQSHLs : N3VInt_QHSD<0,0,0b0100,1, IIC_VSHLi4D, IIC_VSHLi4D, IIC_VSHLi4Q, + IIC_VSHLi4Q, "vqshl", "s", int_arm_neon_vqshifts,0>; +defm VQSHLu : N3VInt_QHSD<1,0,0b0100,1, IIC_VSHLi4D, IIC_VSHLi4D, IIC_VSHLi4Q, + IIC_VSHLi4Q, "vqshl", "u", int_arm_neon_vqshiftu,0>; // VQSHL : Vector Saturating Shift Left (Immediate) -// (disassembly note: this has a different interpretation of the shift amont) -defm VQSHLsi : N2VSh_QHSD2<0,1,0b0111,1, IIC_VSHLi4D, "vqshl", "s", NEONvqshls>; -// (disassembly note: this has a different interpretation of the shift amont) -defm VQSHLui : N2VSh_QHSD2<1,1,0b0111,1, IIC_VSHLi4D, "vqshl", "u", NEONvqshlu>; +defm VQSHLsi : N2VSh_QHSD<0,1,0b0111,1, IIC_VSHLi4D, "vqshl", "s", NEONvqshls>; +defm VQSHLui : N2VSh_QHSD<1,1,0b0111,1, IIC_VSHLi4D, "vqshl", "u", NEONvqshlu>; // VQSHLU : Vector Saturating Shift Left (Immediate, Unsigned) -// (disassembly note: this has a different interpretation of the shift amont) -defm VQSHLsu : N2VSh_QHSD2<1,1,0b0110,1, IIC_VSHLi4D, "vqshlu","s",NEONvqshlsu>; +defm VQSHLsu : N2VSh_QHSD<1,1,0b0110,1, IIC_VSHLi4D, "vqshlu","s",NEONvqshlsu>; // VQSHRN : Vector Saturating Shift Right and Narrow defm VQSHRNs : N2VNSh_HSD<0, 1, 0b1001, 0, 0, 1, IIC_VSHLi4D, "vqshrn", "s", @@ -2696,12 +2397,12 @@ NEONvqshrnsu>; // VQRSHL : Vector Saturating Rounding Shift -defm VQRSHLs : N3VInt_QHSD2<0,0,0b0101,1, IIC_VSHLi4D, IIC_VSHLi4D, IIC_VSHLi4Q, - IIC_VSHLi4Q, "vqrshl", "s", - int_arm_neon_vqrshifts, 0>; -defm VQRSHLu : N3VInt_QHSD2<1,0,0b0101,1, IIC_VSHLi4D, IIC_VSHLi4D, IIC_VSHLi4Q, - IIC_VSHLi4Q, "vqrshl", "u", - int_arm_neon_vqrshiftu, 0>; +defm VQRSHLs : N3VInt_QHSD<0,0,0b0101,1, IIC_VSHLi4D, IIC_VSHLi4D, IIC_VSHLi4Q, + IIC_VSHLi4Q, "vqrshl", "s", + int_arm_neon_vqrshifts, 0>; +defm VQRSHLu : N3VInt_QHSD<1,0,0b0101,1, IIC_VSHLi4D, IIC_VSHLi4D, IIC_VSHLi4Q, + IIC_VSHLi4Q, "vqrshl", "u", + int_arm_neon_vqrshiftu, 0>; // VQRSHRN : Vector Saturating Rounding Shift Right and Narrow defm VQRSHRNs : N2VNSh_HSD<0, 1, 0b1001, 0, 1, 1, IIC_VSHLi4D, "vqrshrn", "s", @@ -2721,8 +2422,7 @@ defm VRSRAu : N2VShAdd_QHSD<1, 1, 0b0011, 1, "vrsra", "u", NEONvrshru>; // VSLI : Vector Shift Left and Insert -// (disassembly note: this has a different interpretation of the shift amont) -defm VSLI : N2VShIns_QHSD2<1, 1, 0b0101, 1, "vsli", NEONvsli>; +defm VSLI : N2VShIns_QHSD<1, 1, 0b0101, 1, "vsli", NEONvsli>; // VSRI : Vector Shift Right and Insert defm VSRI : N2VShIns_QHSD<1, 1, 0b0100, 1, "vsri", NEONvsri>; @@ -2818,13 +2518,10 @@ // VMOV : Vector Move (Register) -// Mark these instructions as 2-register instructions to help the disassembler. -let NSF = NVdVmImmFrm, NSForm = NVdVmImmFrm.Value in { def VMOVDneon: N3VX<0, 0, 0b10, 0b0001, 0, 1, (outs DPR:$dst), (ins DPR:$src), IIC_VMOVD, "vmov", "$dst, $src", "", []>; def VMOVQ : N3VX<0, 0, 0b10, 0b0001, 1, 1, (outs QPR:$dst), (ins QPR:$src), IIC_VMOVD, "vmov", "$dst, $src", "", []>; -} // VMOV : Vector Move (Immediate) @@ -3065,7 +2762,6 @@ // VDUP : Vector Duplicate Lane (from scalar to all elements) -let NSF = NVdVmImmVDupLaneFrm, NSForm = NVdVmImmVDupLaneFrm.Value in { class VDUPLND op19_18, bits<2> op17_16, string OpcodeStr, string Dt, ValueType Ty> : N2V<0b11, 0b11, op19_18, op17_16, 0b11000, 0, 0, @@ -3079,7 +2775,6 @@ (outs QPR:$dst), (ins DPR:$src, nohash_imm:$lane), IIC_VMOVD, OpcodeStr, Dt, "$dst, $src[$lane]", "", [(set QPR:$dst, (ResTy (NEONvduplane (OpTy DPR:$src), imm:$lane)))]>; -} // Inst{19-16} is partially specified depending on the element size. @@ -3148,37 +2843,24 @@ // Vector Conversions. -let NSF = NVdVmImmVCVTFrm, NSForm = NVdVmImmVCVTFrm.Value in { -class N2VDX op24_23, bits<2> op21_20, bits<2> op19_18, - bits<2> op17_16, bits<5> op11_7, bit op4, string OpcodeStr, - string Dt, ValueType ResTy, ValueType OpTy, SDNode OpNode> - : N2VD; -class N2VQX op24_23, bits<2> op21_20, bits<2> op19_18, - bits<2> op17_16, bits<5> op11_7, bit op4, string OpcodeStr, - string Dt, ValueType ResTy, ValueType OpTy, SDNode OpNode> - : N2VQ; -} - // VCVT : Vector Convert Between Floating-Point and Integers -def VCVTf2sd : N2VDX<0b11, 0b11, 0b10, 0b11, 0b01110, 0, "vcvt", "s32.f32", - v2i32, v2f32, fp_to_sint>; -def VCVTf2ud : N2VDX<0b11, 0b11, 0b10, 0b11, 0b01111, 0, "vcvt", "u32.f32", - v2i32, v2f32, fp_to_uint>; -def VCVTs2fd : N2VDX<0b11, 0b11, 0b10, 0b11, 0b01100, 0, "vcvt", "f32.s32", - v2f32, v2i32, sint_to_fp>; -def VCVTu2fd : N2VDX<0b11, 0b11, 0b10, 0b11, 0b01101, 0, "vcvt", "f32.u32", - v2f32, v2i32, uint_to_fp>; - -def VCVTf2sq : N2VQX<0b11, 0b11, 0b10, 0b11, 0b01110, 0, "vcvt", "s32.f32", - v4i32, v4f32, fp_to_sint>; -def VCVTf2uq : N2VQX<0b11, 0b11, 0b10, 0b11, 0b01111, 0, "vcvt", "u32.f32", - v4i32, v4f32, fp_to_uint>; -def VCVTs2fq : N2VQX<0b11, 0b11, 0b10, 0b11, 0b01100, 0, "vcvt", "f32.s32", - v4f32, v4i32, sint_to_fp>; -def VCVTu2fq : N2VQX<0b11, 0b11, 0b10, 0b11, 0b01101, 0, "vcvt", "f32.u32", - v4f32, v4i32, uint_to_fp>; +def VCVTf2sd : N2VD<0b11, 0b11, 0b10, 0b11, 0b01110, 0, "vcvt", "s32.f32", + v2i32, v2f32, fp_to_sint>; +def VCVTf2ud : N2VD<0b11, 0b11, 0b10, 0b11, 0b01111, 0, "vcvt", "u32.f32", + v2i32, v2f32, fp_to_uint>; +def VCVTs2fd : N2VD<0b11, 0b11, 0b10, 0b11, 0b01100, 0, "vcvt", "f32.s32", + v2f32, v2i32, sint_to_fp>; +def VCVTu2fd : N2VD<0b11, 0b11, 0b10, 0b11, 0b01101, 0, "vcvt", "f32.u32", + v2f32, v2i32, uint_to_fp>; + +def VCVTf2sq : N2VQ<0b11, 0b11, 0b10, 0b11, 0b01110, 0, "vcvt", "s32.f32", + v4i32, v4f32, fp_to_sint>; +def VCVTf2uq : N2VQ<0b11, 0b11, 0b10, 0b11, 0b01111, 0, "vcvt", "u32.f32", + v4i32, v4f32, fp_to_uint>; +def VCVTs2fq : N2VQ<0b11, 0b11, 0b10, 0b11, 0b01100, 0, "vcvt", "f32.s32", + v4f32, v4i32, sint_to_fp>; +def VCVTu2fq : N2VQ<0b11, 0b11, 0b10, 0b11, 0b01101, 0, "vcvt", "f32.u32", + v4f32, v4i32, uint_to_fp>; // VCVT : Vector Convert Between Floating-Point and Fixed-Point. def VCVTf2xsd : N2VCvtD<0, 1, 0b1111, 0, 1, "vcvt", "s32.f32", @@ -3263,8 +2945,6 @@ // VEXT : Vector Extract -let NSF = NVdVnVmImmVectorExtractFrm, - NSForm = NVdVnVmImmVectorExtractFrm.Value in { class VEXTd : N3V<0,1,0b11,{?,?,?,?},0,0, (outs DPR:$dst), (ins DPR:$lhs, DPR:$rhs, i32imm:$index), IIC_VEXTD, @@ -3278,7 +2958,6 @@ OpcodeStr, Dt, "$dst, $lhs, $rhs, $index", "", [(set QPR:$dst, (Ty (NEONvext (Ty QPR:$lhs), (Ty QPR:$rhs), imm:$index)))]>; -} def VEXTd8 : VEXTd<"vext", "8", v8i8>; def VEXTd16 : VEXTd<"vext", "16", v4i16>; @@ -3322,8 +3001,6 @@ // Vector Table Lookup and Table Extension. -let NSF = VTBLFrm, NSForm = VTBLFrm.Value in { - // VTBL : Vector Table Lookup def VTBL1 : N3V<1,1,0b11,0b1000,0,0, (outs DPR:$dst), @@ -3380,8 +3057,6 @@ DPR:$tbl2, DPR:$tbl3, DPR:$tbl4, DPR:$src)))]>; } // hasExtraSrcRegAllocReq = 1 -} // End of "let NSF = VTBLFrm, ..." - //===----------------------------------------------------------------------===// // NEON instructions for single-precision FP math //===----------------------------------------------------------------------===// From dpatel at apple.com Wed Mar 17 18:52:37 2010 From: dpatel at apple.com (Devang Patel) Date: Wed, 17 Mar 2010 23:52:37 -0000 Subject: [llvm-commits] [llvm] r98778 - /llvm/trunk/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp Message-ID: <20100317235237.9F8712A6C12C@llvm.org> Author: dpatel Date: Wed Mar 17 18:52:37 2010 New Revision: 98778 URL: http://llvm.org/viewvc/llvm-project?rev=98778&view=rev Log: Debug info intrinsic does not intefer during tail call optimization. Modified: llvm/trunk/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp Modified: llvm/trunk/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp?rev=98778&r1=98777&r2=98778&view=diff ============================================================================== --- llvm/trunk/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp (original) +++ llvm/trunk/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp Wed Mar 17 18:52:37 2010 @@ -4282,6 +4282,9 @@ --BBI) { if (&*BBI == I) break; + // Debug info intrinsic does not intefer during tail call optimization. + if (isa(BBI)) + continue; if (BBI->mayHaveSideEffects() || BBI->mayReadFromMemory() || !BBI->isSafeToSpeculativelyExecute()) return false; From evan.cheng at apple.com Wed Mar 17 18:58:36 2010 From: evan.cheng at apple.com (Evan Cheng) Date: Wed, 17 Mar 2010 23:58:36 -0000 Subject: [llvm-commits] [llvm] r98780 - in /llvm/trunk: lib/Target/X86/X86ISelDAGToDAG.cpp test/CodeGen/X86/2010-03-17-ISelBug.ll Message-ID: <20100317235836.2B4952A6C12C@llvm.org> Author: evancheng Date: Wed Mar 17 18:58:35 2010 New Revision: 98780 URL: http://llvm.org/viewvc/llvm-project?rev=98780&view=rev Log: X86 address mode matching code MatchAddressRecursively does some aggressive hack which require doing a RAUW. It may end up deleting some SDNode up stream. It should avoid referencing deleted nodes. Added: llvm/trunk/test/CodeGen/X86/2010-03-17-ISelBug.ll Modified: llvm/trunk/lib/Target/X86/X86ISelDAGToDAG.cpp Modified: llvm/trunk/lib/Target/X86/X86ISelDAGToDAG.cpp URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Target/X86/X86ISelDAGToDAG.cpp?rev=98780&r1=98779&r2=98780&view=diff ============================================================================== --- llvm/trunk/lib/Target/X86/X86ISelDAGToDAG.cpp (original) +++ llvm/trunk/lib/Target/X86/X86ISelDAGToDAG.cpp Wed Mar 17 18:58:35 2010 @@ -140,6 +140,21 @@ } namespace { + class X86ISelListener : public SelectionDAG::DAGUpdateListener { + SmallSet Deletes; + public: + explicit X86ISelListener() {} + virtual void NodeDeleted(SDNode *N, SDNode *E) { + Deletes.insert(N); + } + virtual void NodeUpdated(SDNode *N) { + // Ignore updates. + } + bool IsDeleted(SDNode *N) { + return Deletes.count(N); + } + }; + //===--------------------------------------------------------------------===// /// ISel - X86 specific code to select X86 machine instructions for /// SelectionDAG operations. @@ -187,6 +202,7 @@ bool MatchWrapper(SDValue N, X86ISelAddressMode &AM); bool MatchAddress(SDValue N, X86ISelAddressMode &AM); bool MatchAddressRecursively(SDValue N, X86ISelAddressMode &AM, + X86ISelListener &DeadNodes, unsigned Depth); bool MatchAddressBase(SDValue N, X86ISelAddressMode &AM); bool SelectAddr(SDNode *Op, SDValue N, SDValue &Base, @@ -651,7 +667,8 @@ /// returning true if it cannot be done. This just pattern matches for the /// addressing mode. bool X86DAGToDAGISel::MatchAddress(SDValue N, X86ISelAddressMode &AM) { - if (MatchAddressRecursively(N, AM, 0)) + X86ISelListener DeadNodes; + if (MatchAddressRecursively(N, AM, DeadNodes, 0)) return true; // Post-processing: Convert lea(,%reg,2) to lea(%reg,%reg), which has @@ -680,6 +697,7 @@ } bool X86DAGToDAGISel::MatchAddressRecursively(SDValue N, X86ISelAddressMode &AM, + X86ISelListener &DeadNodes, unsigned Depth) { bool is64Bit = Subtarget->is64Bit(); DebugLoc dl = N.getDebugLoc(); @@ -845,7 +863,11 @@ // Test if the LHS of the sub can be folded. X86ISelAddressMode Backup = AM; - if (MatchAddressRecursively(N.getNode()->getOperand(0), AM, Depth+1)) { + if (MatchAddressRecursively(N.getNode()->getOperand(0), AM, + DeadNodes, Depth+1) || + // If it is successful but the recursive update causes N to be deleted, + // then it's not safe to continue. + DeadNodes.IsDeleted(N.getNode())) { AM = Backup; break; } @@ -854,6 +876,7 @@ AM = Backup; break; } + int Cost = 0; SDValue RHS = N.getNode()->getOperand(1); // If the RHS involves a register with multiple uses, this @@ -907,13 +930,33 @@ case ISD::ADD: { X86ISelAddressMode Backup = AM; - if (!MatchAddressRecursively(N.getNode()->getOperand(0), AM, Depth+1) && - !MatchAddressRecursively(N.getNode()->getOperand(1), AM, Depth+1)) - return false; + if (!MatchAddressRecursively(N.getNode()->getOperand(0), AM, + DeadNodes, Depth+1)) { + if (DeadNodes.IsDeleted(N.getNode())) + // If it is successful but the recursive update causes N to be deleted, + // then it's not safe to continue. + return true; + if (!MatchAddressRecursively(N.getNode()->getOperand(1), AM, + DeadNodes, Depth+1)) + // If it is successful but the recursive update causes N to be deleted, + // then it's not safe to continue. + return DeadNodes.IsDeleted(N.getNode()); + } + + // Try again after commuting the operands. AM = Backup; - if (!MatchAddressRecursively(N.getNode()->getOperand(1), AM, Depth+1) && - !MatchAddressRecursively(N.getNode()->getOperand(0), AM, Depth+1)) - return false; + if (!MatchAddressRecursively(N.getNode()->getOperand(1), AM, + DeadNodes, Depth+1)) { + if (DeadNodes.IsDeleted(N.getNode())) + // If it is successful but the recursive update causes N to be deleted, + // then it's not safe to continue. + return true; + if (!MatchAddressRecursively(N.getNode()->getOperand(0), AM, + DeadNodes, Depth+1)) + // If it is successful but the recursive update causes N to be deleted, + // then it's not safe to continue. + return DeadNodes.IsDeleted(N.getNode()); + } AM = Backup; // If we couldn't fold both operands into the address at the same time, @@ -935,16 +978,19 @@ if (ConstantSDNode *CN = dyn_cast(N.getOperand(1))) { X86ISelAddressMode Backup = AM; uint64_t Offset = CN->getSExtValue(); + + // Check to see if the LHS & C is zero. + if (!CurDAG->MaskedValueIsZero(N.getOperand(0), CN->getAPIntValue())) + break; + // Start with the LHS as an addr mode. - if (!MatchAddressRecursively(N.getOperand(0), AM, Depth+1) && + if (!MatchAddressRecursively(N.getOperand(0), AM, DeadNodes, Depth+1) && // Address could not have picked a GV address for the displacement. AM.GV == NULL && // On x86-64, the resultant disp must fit in 32-bits. (!is64Bit || X86::isOffsetSuitableForCodeModel(AM.Disp + Offset, M, - AM.hasSymbolicDisplacement())) && - // Check to see if the LHS & C is zero. - CurDAG->MaskedValueIsZero(N.getOperand(0), CN->getAPIntValue())) { + AM.hasSymbolicDisplacement()))) { AM.Disp += Offset; return false; } @@ -1015,7 +1061,7 @@ CurDAG->RepositionNode(N.getNode(), Shl.getNode()); Shl.getNode()->setNodeId(N.getNode()->getNodeId()); } - CurDAG->ReplaceAllUsesWith(N, Shl); + CurDAG->ReplaceAllUsesWith(N, Shl, &DeadNodes); AM.IndexReg = And; AM.Scale = (1 << ScaleLog); return false; @@ -1066,7 +1112,7 @@ NewSHIFT.getNode()->setNodeId(N.getNode()->getNodeId()); } - CurDAG->ReplaceAllUsesWith(N, NewSHIFT); + CurDAG->ReplaceAllUsesWith(N, NewSHIFT, &DeadNodes); AM.Scale = 1 << ShiftCst; AM.IndexReg = NewAND; Added: llvm/trunk/test/CodeGen/X86/2010-03-17-ISelBug.ll URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/CodeGen/X86/2010-03-17-ISelBug.ll?rev=98780&view=auto ============================================================================== --- llvm/trunk/test/CodeGen/X86/2010-03-17-ISelBug.ll (added) +++ llvm/trunk/test/CodeGen/X86/2010-03-17-ISelBug.ll Wed Mar 17 18:58:35 2010 @@ -0,0 +1,39 @@ +; RUN: llc < %s -mtriple=i386-apple-darwin5 +; rdar://7761790 + +%"struct..0$_485" = type { i16, i16, i32 } +%union.PPToken = type { %"struct..0$_485" } +%struct.PPOperation = type { %union.PPToken, %union.PPToken, [6 x %union.PPToken], i32, i32, i32, [1 x i32], [0 x i8] } + +define i32* @t() align 2 nounwind { +entry: + %operation = alloca %struct.PPOperation, align 8 ; <%struct.PPOperation*> [#uses=2] + %0 = load i32*** null, align 4 ; [#uses=1] + %1 = ptrtoint i32** %0 to i32 ; [#uses=1] + %2 = sub nsw i32 %1, undef ; [#uses=2] + br i1 false, label %bb20, label %bb.nph380 + +bb20: ; preds = %entry + ret i32* null + +bb.nph380: ; preds = %entry + %scevgep403 = getelementptr %struct.PPOperation* %operation, i32 0, i32 1, i32 0, i32 2 ; [#uses=1] + %3 = ashr i32 %2, 1 ; [#uses=1] + %tmp405 = and i32 %3, -2 ; [#uses=1] + %scevgep408 = getelementptr %struct.PPOperation* %operation, i32 0, i32 1, i32 0, i32 1 ; [#uses=1] + %tmp410 = and i32 %2, -4 ; [#uses=1] + br label %bb169 + +bb169: ; preds = %bb169, %bb.nph380 + %index.6379 = phi i32 [ 0, %bb.nph380 ], [ %4, %bb169 ] ; [#uses=3] + %tmp404 = mul i32 %index.6379, -2 ; [#uses=1] + %tmp406 = add i32 %tmp405, %tmp404 ; [#uses=1] + %scevgep407 = getelementptr i32* %scevgep403, i32 %tmp406 ; [#uses=1] + %tmp409 = mul i32 %index.6379, -4 ; [#uses=1] + %tmp411 = add i32 %tmp410, %tmp409 ; [#uses=1] + %scevgep412 = getelementptr i16* %scevgep408, i32 %tmp411 ; [#uses=1] + store i16 undef, i16* %scevgep412, align 2 + store i32 undef, i32* %scevgep407, align 4 + %4 = add nsw i32 %index.6379, 1 ; [#uses=1] + br label %bb169 +} From andrewl at lenharth.org Wed Mar 17 19:03:53 2010 From: andrewl at lenharth.org (Andrew Lenharth) Date: Thu, 18 Mar 2010 00:03:53 -0000 Subject: [llvm-commits] [poolalloc] r98781 - in /poolalloc/trunk: include/dsa/DSCallGraph.h include/dsa/DataStructure.h include/dsa/svset.h lib/DSA/BottomUpClosure.cpp lib/DSA/CompleteBottomUp.cpp lib/DSA/DataStructure.cpp lib/DSA/Local.cpp Message-ID: <20100318000354.116962A6C12C@llvm.org> Author: alenhar2 Date: Wed Mar 17 19:03:53 2010 New Revision: 98781 URL: http://llvm.org/viewvc/llvm-project?rev=98781&view=rev Log: Use generic EquivalenceClass to store SCCs and clean up the mess that was DSSCCGraph Modified: poolalloc/trunk/include/dsa/DSCallGraph.h poolalloc/trunk/include/dsa/DataStructure.h poolalloc/trunk/include/dsa/svset.h poolalloc/trunk/lib/DSA/BottomUpClosure.cpp poolalloc/trunk/lib/DSA/CompleteBottomUp.cpp poolalloc/trunk/lib/DSA/DataStructure.cpp poolalloc/trunk/lib/DSA/Local.cpp Modified: poolalloc/trunk/include/dsa/DSCallGraph.h URL: http://llvm.org/viewvc/llvm-project/poolalloc/trunk/include/dsa/DSCallGraph.h?rev=98781&r1=98780&r2=98781&view=diff ============================================================================== --- poolalloc/trunk/include/dsa/DSCallGraph.h (original) +++ poolalloc/trunk/include/dsa/DSCallGraph.h Wed Mar 17 19:03:53 2010 @@ -18,10 +18,10 @@ #include "dsa/keyiterator.h" #include -#include "llvm/Function.h" -#include "llvm/DerivedTypes.h" +//Fix in 2.8, EQC includes cassert +#include +#include "llvm/ADT/EquivalenceClasses.h" #include "llvm/Support/CallSite.h" -#include "llvm/Support/FormattedStream.h" class DSCallGraph { @@ -31,31 +31,44 @@ typedef std::map SimpleCalleesTy; private: + //ActualCallees contains CallSite -> Function mappings ActualCalleesTy ActualCallees; + //SimpleCallees contains Function -> Function mappings SimpleCalleesTy SimpleCallees; + //These are used for returning empty sets when the caller has no callees FuncSet EmptyActual; FuncSet EmptySimple; + //An equivalence class is exactly an SCC + llvm::EquivalenceClasses SCCs; + + //Functions we know about that aren't called + svset knownRoots; + + //Types for SCC construction + typedef std::map TFMap; + typedef std::vector TFStack; + + // Tarjan's SCC algorithm + unsigned tarjan_rec(const llvm::Function* F, TFStack& Stack, unsigned &NextID, + TFMap& ValMap); + + void removeECFunctions(); + public: DSCallGraph() {} typedef ActualCalleesTy::mapped_type::const_iterator callee_iterator; - typedef KeyIterator key_iterator; + typedef KeyIterator callee_key_iterator; typedef SimpleCalleesTy::mapped_type::const_iterator flat_iterator; typedef KeyIterator flat_key_iterator; + typedef FuncSet::const_iterator root_iterator; + typedef llvm::EquivalenceClasses::member_iterator scc_iterator; - void insert(llvm::CallSite CS, const llvm::Function* F) { - if (F) { - ActualCallees[CS].insert(F); - SimpleCallees[CS.getInstruction()->getParent()->getParent()].insert(F); - //Create an empty set for the callee, hence all called functions get to be - // in the call graph also. This simplifies SCC formation - SimpleCallees[F]; - } - } - + void insert(llvm::CallSite CS, const llvm::Function* F); + template void insert(llvm::CallSite CS, Iterator _begin, Iterator _end) { for (; _begin != _end; ++_begin) @@ -76,12 +89,12 @@ return ii->second.end(); } - key_iterator key_begin() const { - return key_iterator(ActualCallees.begin()); + callee_key_iterator key_begin() const { + return callee_key_iterator(ActualCallees.begin()); } - key_iterator key_end() const { - return key_iterator(ActualCallees.end()); + callee_key_iterator key_end() const { + return callee_key_iterator(ActualCallees.end()); } flat_iterator flat_callee_begin(const llvm::Function* F) const { @@ -106,6 +119,24 @@ return flat_key_iterator(SimpleCallees.end()); } + root_iterator root_begin() const { + return knownRoots.begin(); + } + + root_iterator root_end() const { + return knownRoots.end(); + } + + scc_iterator scc_begin(const llvm::Function* F) const { + assert(F == SCCs.getLeaderValue(F) && "Requested non-leader"); + return SCCs.member_begin(SCCs.findValue(F)); + } + + scc_iterator scc_end(const llvm::Function* F) const { + assert(F == SCCs.getLeaderValue(F) && "Requested non-leader"); + return SCCs.member_end(); + } + unsigned callee_size(llvm::CallSite CS) const { ActualCalleesTy::const_iterator ii = ActualCallees.find(CS); @@ -122,196 +153,19 @@ return sum; } - void clear() { - ActualCallees.clear(); - } - -}; - -class DSSCCGraph { -public: - //SCCs, each element is an SCC - std::map SCCs; - //mapping of functions in SCCs to SCCs index - std::map invmap; - - unsigned nextSCC; + void buildSCCs(); - //Functions we know about that aren't called - svset knownRoots; - - std::map > SCCCallees; - std::map > ExtCallees; - - DSCallGraph oldGraph; - -private: - typedef std::map TFMap; - typedef std::vector TFStack; + void buildRoots(); - bool hasPointers(const llvm::Function* F) { - if (F->isVarArg()) return true; - if (F->getReturnType()->isPointerTy()) return true; - for (llvm::Function::const_arg_iterator ii = F->arg_begin(), ee = F->arg_end(); - ii != ee; ++ii) - if (ii->getType()->isPointerTy()) return true; - return false; - } + void dump(); - unsigned tarjan_rec(const llvm::Function* F, TFStack& Stack, unsigned &NextID, - TFMap& ValMap, DSCallGraph& cg) { - assert(!ValMap.count(F) && "Shouldn't revisit functions!"); - unsigned Min = NextID++, MyID = Min; - ValMap[F] = Min; - Stack.push_back(F); - - // The edges out of the current node are the call site targets... - for (DSCallGraph::flat_iterator ii = cg.flat_callee_begin(F), - ee = cg.flat_callee_end(F); ii != ee; ++ii) { - if (hasPointers(*ii) && !(*ii)->isDeclaration()) { - unsigned M = Min; - // Have we visited the destination function yet? - TFMap::iterator It = ValMap.find(*ii); - if (It == ValMap.end()) // No, visit it now. - M = tarjan_rec(*ii, Stack, NextID, ValMap, cg); - else if (std::find(Stack.begin(), Stack.end(), *ii) != Stack.end()) - M = It->second; - if (M < Min) Min = M; - } - } - - assert(ValMap[F] == MyID && "SCC construction assumption wrong!"); - if (Min != MyID) - return Min; // This is part of a larger SCC! - - // If this is a new SCC, process it now. - ++nextSCC; - - const llvm::Function* NF = 0; - do { - NF = Stack.back(); - Stack.pop_back(); - assert(NF && "Null Function"); - assert(invmap.find(NF) == invmap.end() && "Function already in invmap"); - invmap[NF] = nextSCC; - assert(SCCs[nextSCC].find(NF) == SCCs[nextSCC].end() && - "Function already in SCC"); - SCCs[nextSCC].insert(NF); - } while (NF != F); - - return MyID; - } - - void buildSCC(DSCallGraph& DSG) { - TFStack Stack; - TFMap ValMap; - unsigned NextID = 1; - - for (DSCallGraph::flat_key_iterator ii = DSG.flat_key_begin(), - ee = DSG.flat_key_end(); ii != ee; ++ii) - if (!ValMap.count(*ii)) - tarjan_rec(*ii, Stack, NextID, ValMap, DSG); - } - - void buildCallGraph(DSCallGraph& DSG) { - for(DSCallGraph::flat_key_iterator ii = DSG.flat_key_begin(), - ee = DSG.flat_key_end(); ii != ee; ++ii) { - assert (*ii && "Null Function"); - assert(invmap.find(*ii) != invmap.end() && "Unknown Function"); - for (DSCallGraph::flat_iterator fi = DSG.flat_callee_begin(*ii), - fe = DSG.flat_callee_end(*ii); fi != fe; ++fi) { - assert(*fi && "Null Function"); - assert(invmap.find(*fi) != invmap.end() && "Unknown Function"); - if (invmap[*ii] != invmap[*fi]) // No self calls - if (hasPointers(*fi)) { - if ((*fi)->isDeclaration()) - ExtCallees[invmap[*ii]].insert(invmap[*fi]); - else - SCCCallees[invmap[*ii]].insert(invmap[*fi]); - } - } - } - } - - void buildRoots() { - svset knownCallees; - svset knownCallers; - for (std::map >::iterator - ii = SCCCallees.begin(), ee = SCCCallees.end(); ii != ee; ++ii) { - knownCallees.insert(ii->second.begin(), ii->second.end()); - knownCallers.insert(ii->first); - } - for (svset::iterator ii = knownCallers.begin(), - ee = knownCallers.end(); ii != ee; ++ii) - if (!knownCallees.count(*ii)) - knownRoots.insert(*ii); - } - - void assertMapValid() { - for (std::map::iterator ii = SCCs.begin(), - ee = SCCs.end(); ii != ee; ++ii) { - for (DSCallGraph::FuncSet::iterator i = ii->second.begin(), - e = ii->second.end(); i != e; ++i) { - assert(*i && "Null Function in map"); - assert(invmap.find(*i) != invmap.end() && "Function not in invmap"); - assert(invmap[*i] == ii->first && "invmap doesn't match map"); - } - } - - for (std::map::iterator ii = invmap.begin(), - ee = invmap.end(); ii != ee; ++ii) { - assert(ii->first && "Null Function in invmap"); - assert(SCCs.find(ii->second) != SCCs.end() && "Function in invmap but not in map"); - assert(SCCs[ii->second].count(ii->first) && "SCC doesn't contain function"); - } + void assertSCCRoot(const llvm::Function* F) { + assert(F == SCCs.getLeaderValue(F) && "Not Leader?"); } -public: - - DSSCCGraph(DSCallGraph& DSG) :nextSCC(0) { - oldGraph = DSG; - - buildSCC(DSG); - assertMapValid(); - - buildCallGraph(DSG); - - buildRoots(); - - } - - void dump() { - //function map - for (std::map::iterator ii = SCCs.begin(), - ee = SCCs.end(); ii != ee; ++ii) { - llvm::errs() << "Functions in " << ii->first << ":"; - for (DSCallGraph::FuncSet::iterator i = ii->second.begin(), - e = ii->second.end(); i != e; ++i) - llvm::errs() << " " << *i << "(" << invmap[*i] << ")"; - llvm::errs() << "\n"; - } - -// for (std::map::iterator ii = invmap.begin(), -// ee = invmap.end(); ii != ee; ++ii) -// llvm::errs() << ii->first << " -> " << ii->second << "\n"; - - //SCC map - for (std::map >::iterator ii = SCCCallees.begin(), - ee = SCCCallees.end(); ii != ee; ++ii) { - llvm::errs() << "CallGraph[" << ii->first << "]"; - for (svset::iterator i = ii->second.begin(), - e = ii->second.end(); i != e; ++i) - llvm::errs() << " " << *i; - llvm::errs() << "\n"; - } - - //Functions we know about that aren't called - llvm::errs() << "Roots:"; - for (svset::iterator ii = knownRoots.begin(), - ee = knownRoots.end(); ii != ee; ++ii) - llvm::errs() << " " << *ii; - llvm::errs() << "\n"; - } + //common helper, no good reason for it to be here rather than elsewhere + static bool hasPointers(const llvm::Function* F); + static bool hasPointers(llvm::CallSite& CS); }; Modified: poolalloc/trunk/include/dsa/DataStructure.h URL: http://llvm.org/viewvc/llvm-project/poolalloc/trunk/include/dsa/DataStructure.h?rev=98781&r1=98780&r2=98781&view=diff ============================================================================== --- poolalloc/trunk/include/dsa/DataStructure.h (original) +++ poolalloc/trunk/include/dsa/DataStructure.h Wed Mar 17 19:03:53 2010 @@ -235,11 +235,12 @@ bool runOnModuleInternal(Module &M); private: - void mergeSCCs(DSSCCGraph& DSG); + void mergeSCCs(); - DSGraph* postOrder(DSSCCGraph& DSG, unsigned scc, svset& marked); + DSGraph* postOrder(const Function*, + svset& marked); - void calculateGraph(DSGraph* G, DSSCCGraph& DSG); + void calculateGraph(DSGraph* G); void CloneAuxIntoGlobal(DSGraph* G); void cloneGlobalsInto(DSGraph* G); Modified: poolalloc/trunk/include/dsa/svset.h URL: http://llvm.org/viewvc/llvm-project/poolalloc/trunk/include/dsa/svset.h?rev=98781&r1=98780&r2=98781&view=diff ============================================================================== --- poolalloc/trunk/include/dsa/svset.h (original) +++ poolalloc/trunk/include/dsa/svset.h Wed Mar 17 19:03:53 2010 @@ -134,6 +134,11 @@ return std::make_pair(i, insertion); } + /// Insert a value into the sorted vector. + iterator insert(iterator position, const value_type& x) { + return insert(x).first; + } + /// Insert a range. template < typename Iterator > void insert(Iterator _begin, Iterator _end) { Modified: poolalloc/trunk/lib/DSA/BottomUpClosure.cpp URL: http://llvm.org/viewvc/llvm-project/poolalloc/trunk/lib/DSA/BottomUpClosure.cpp?rev=98781&r1=98780&r2=98781&view=diff ============================================================================== --- poolalloc/trunk/lib/DSA/BottomUpClosure.cpp (original) +++ poolalloc/trunk/lib/DSA/BottomUpClosure.cpp Wed Mar 17 19:03:53 2010 @@ -55,25 +55,26 @@ // entry-points correctly. As a bonus, we can be more aggressive at propagating // information upwards, as long as we don't remove unresolved call sites. bool BUDataStructures::runOnModuleInternal(Module& M) { - //Find SCCs and make SCC call graph - DSSCCGraph DSG(callgraph); + llvm::errs() << "BU is currently being worked in in very invasive ways.\n" + << "It is probably broken right now\n"; - errs() << "DSNode: " << sizeof(DSNode) << "\nDSCallSite: " - << sizeof(DSCallSite) << "\n"; + //Find SCCs and make SCC call graph + callgraph.buildSCCs(); + callgraph.buildRoots(); -// DSG.dump(); + // callgraph.dump(); //merge SCCs - mergeSCCs(DSG); + mergeSCCs(); //Post order traversal: { //errs() << *DSG.knownRoots.begin() << " -> " << *DSG.knownRoots.rbegin() << "\n"; - svset marked; - for (svset::const_iterator ii = DSG.knownRoots.begin(), - ee = DSG.knownRoots.end(); ii != ee; ++ii) { - //errs() << *ii << " "; - DSGraph* G = postOrder(DSG, *ii, marked); + svset marked; + for (DSCallGraph::root_iterator ii = callgraph.root_begin(), + ee = callgraph.root_end(); ii != ee; ++ii) { + errs() << (*ii)->getName() << " "; + DSGraph* G = postOrder(*ii, marked); CloneAuxIntoGlobal(G); } } @@ -164,22 +165,23 @@ return false; } -void BUDataStructures::mergeSCCs(DSSCCGraph& DSG) { +void BUDataStructures::mergeSCCs() { - for (std::map::iterator ii = DSG.SCCs.begin(), - ee = DSG.SCCs.end(); ii != ee; ++ii) { + for (DSCallGraph::flat_key_iterator ii = callgraph.flat_key_begin(), + ee = callgraph.flat_key_end(); ii != ee; ++ii) { + // Externals can be singleton SCCs + if ((*ii)->isDeclaration()) continue; + DSGraph* SCCGraph = getOrCreateGraph(*ii); + unsigned SCCSize = 1; + callgraph.assertSCCRoot(*ii); - DSGraph* SCCGraph = 0; - unsigned SCCSize = 0; - for (DSCallGraph::FuncSet::iterator Fi = ii->second.begin(), - Fe = ii->second.end(); Fi != Fe; ++Fi) { + for (DSCallGraph::scc_iterator Fi = callgraph.scc_begin(*ii), + Fe = callgraph.scc_end(*ii); Fi != Fe; ++Fi) { const Function* F = *Fi; if (F->isDeclaration()) continue; + if (F == *ii) continue; ++SCCSize; DSGraph* NFG = getOrCreateGraph(F); - if (!SCCGraph) { - SCCGraph = NFG; - } if (NFG != SCCGraph) { ++NumSCCMerges; // Update the Function -> DSG map. @@ -195,17 +197,22 @@ } } -DSGraph* BUDataStructures::postOrder(DSSCCGraph& DSG, unsigned scc, - svset& marked) { - DSGraph* G = getDSGraph(**DSG.SCCs[scc].begin()); - if (marked.count(scc)) return G; - - for(svset::iterator ii = DSG.SCCCallees[scc].begin(), - ee = DSG.SCCCallees[scc].end(); ii != ee; ++ii) - postOrder(DSG, *ii, marked); +DSGraph* BUDataStructures::postOrder(const Function* F, + svset& marked) { + callgraph.assertSCCRoot(F); + DSGraph* G = getDSGraph(*F); + if (marked.count(F)) return G; + + for(DSCallGraph::flat_iterator ii = callgraph.flat_callee_begin(F), + ee = callgraph.flat_callee_end(F); ii != ee; ++ii) { + callgraph.assertSCCRoot(*ii); + assert (*ii != F && "Simple loop in callgraph"); + if (!(*ii)->isDeclaration()) + postOrder(*ii, marked); + } - marked.insert(scc); - calculateGraph(G, DSG); + marked.insert(F); + calculateGraph(G); return G; } @@ -262,7 +269,7 @@ } } -void BUDataStructures::calculateGraph(DSGraph* Graph, DSSCCGraph& DSG) { +void BUDataStructures::calculateGraph(DSGraph* Graph) { DEBUG(Graph->AssertGraphOK(); Graph->getGlobalsGraph()->AssertGraphOK()); // If this graph contains the main function, clone the globals graph into this @@ -281,8 +288,8 @@ // Note that this is *required* for correctness. If a callee contains a use // of a global, we have to make sure to link up nodes due to global-argument // bindings. - if (ContainsMain) - cloneGlobalsInto(Graph); +// if (ContainsMain) +// cloneGlobalsInto(Graph); // Move our call site list into TempFCs so that inline call sites go into the // new call site list and doesn't invalidate our iterators! @@ -305,8 +312,8 @@ continue; } - std::copy(DSG.oldGraph.callee_begin(CS.getCallSite()), - DSG.oldGraph.callee_end(CS.getCallSite()), + std::copy(callgraph.callee_begin(CS.getCallSite()), + callgraph.callee_end(CS.getCallSite()), std::back_inserter(CalledFuncs)); std::vector::iterator ErasePoint = Modified: poolalloc/trunk/lib/DSA/CompleteBottomUp.cpp URL: http://llvm.org/viewvc/llvm-project/poolalloc/trunk/lib/DSA/CompleteBottomUp.cpp?rev=98781&r1=98780&r2=98781&view=diff ============================================================================== --- poolalloc/trunk/lib/DSA/CompleteBottomUp.cpp (original) +++ poolalloc/trunk/lib/DSA/CompleteBottomUp.cpp Wed Mar 17 19:03:53 2010 @@ -49,7 +49,7 @@ DSGraph::ScalarMapTy& SM = G->getScalarMap(); //mege nodes in the global graph for these functions - for (DSCallGraph::key_iterator ii = callgraph.key_begin(), + for (DSCallGraph::callee_key_iterator ii = callgraph.key_begin(), ee = callgraph.key_end(); ii != ee; ++ii) { DSCallGraph::callee_iterator csi = callgraph.callee_begin(*ii), cse = callgraph.callee_end(*ii); Modified: poolalloc/trunk/lib/DSA/DataStructure.cpp URL: http://llvm.org/viewvc/llvm-project/poolalloc/trunk/lib/DSA/DataStructure.cpp?rev=98781&r1=98780&r2=98781&view=diff ============================================================================== --- poolalloc/trunk/lib/DSA/DataStructure.cpp (original) +++ poolalloc/trunk/lib/DSA/DataStructure.cpp Wed Mar 17 19:03:53 2010 @@ -1268,7 +1268,8 @@ // Empty map so next time memory is released, data structures are not // re-deleted. DSInfo.clear(); - callgraph.clear(); + //FIXME: +// callgraph.clear(); delete GlobalsGraph; GlobalsGraph = 0; } Modified: poolalloc/trunk/lib/DSA/Local.cpp URL: http://llvm.org/viewvc/llvm-project/poolalloc/trunk/lib/DSA/Local.cpp?rev=98781&r1=98780&r2=98781&view=diff ============================================================================== --- poolalloc/trunk/lib/DSA/Local.cpp (original) +++ poolalloc/trunk/lib/DSA/Local.cpp Wed Mar 17 19:03:53 2010 @@ -749,7 +749,14 @@ if (visitAllocation(CS)) return; + //Can't do much about inline asm (yet!) if (isa(CS.getCalledValue())) return; + + //uninteresting call + if (!DSCallGraph::hasPointers(CS)) + return; + + // if (InlineAsm* IASM = dyn_cast(CS.getCalledValue())) { // if (IASM->hasSideEffects()) // errs() << ASM w/ Side Effects\n"; From stoklund at 2pi.dk Wed Mar 17 19:23:48 2010 From: stoklund at 2pi.dk (Jakob Stoklund Olesen) Date: Thu, 18 Mar 2010 00:23:48 -0000 Subject: [llvm-commits] [llvm] r98784 - /llvm/trunk/lib/CodeGen/SimpleRegisterCoalescing.cpp Message-ID: <20100318002348.288062A6C12C@llvm.org> Author: stoklund Date: Wed Mar 17 19:23:47 2010 New Revision: 98784 URL: http://llvm.org/viewvc/llvm-project?rev=98784&view=rev Log: Revert "Change coalescer complexity from N^2 to N logN by changing one letter." This reverts commit 98776. It broke the llvm-gcc boot strap. Modified: llvm/trunk/lib/CodeGen/SimpleRegisterCoalescing.cpp Modified: llvm/trunk/lib/CodeGen/SimpleRegisterCoalescing.cpp URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/CodeGen/SimpleRegisterCoalescing.cpp?rev=98784&r1=98783&r2=98784&view=diff ============================================================================== --- llvm/trunk/lib/CodeGen/SimpleRegisterCoalescing.cpp (original) +++ llvm/trunk/lib/CodeGen/SimpleRegisterCoalescing.cpp Wed Mar 17 19:23:47 2010 @@ -1682,9 +1682,20 @@ // density, do not join them, instead mark the physical register as its // allocation preference. LiveInterval &JoinVInt = SrcIsPhys ? DstInt : SrcInt; + LiveInterval &JoinPInt = SrcIsPhys ? SrcInt : DstInt; unsigned JoinVReg = SrcIsPhys ? DstReg : SrcReg; unsigned JoinPReg = SrcIsPhys ? SrcReg : DstReg; + // Don't join with physregs that have a ridiculous number of live + // ranges. The data structure performance is really bad when that + // happens. + if (JoinPInt.ranges.size() > 1000) { + mri_->setRegAllocationHint(JoinVInt.reg, 0, JoinPReg); + ++numAborts; + DEBUG(dbgs() << "\tPhysical register too complicated, abort!\n"); + return false; + } + const TargetRegisterClass *RC = mri_->getRegClass(JoinVReg); unsigned Threshold = allocatableRCRegs_[RC].count() * 2; unsigned Length = li_->getApproximateInstructionCount(JoinVInt); @@ -2159,7 +2170,7 @@ // Update the liveintervals of sub-registers. if (TargetRegisterInfo::isPhysicalRegister(LHS.reg)) for (const unsigned *AS = tri_->getSubRegisters(LHS.reg); *AS; ++AS) - li_->getOrCreateInterval(*AS).MergeInClobberRanges(*li_, RHS, + li_->getOrCreateInterval(*AS).MergeInClobberRanges(*li_, LHS, li_->getVNInfoAllocator()); return true; From tonic at nondot.org Wed Mar 17 19:56:39 2010 From: tonic at nondot.org (Tanya Lattner) Date: Thu, 18 Mar 2010 00:56:39 -0000 Subject: [llvm-commits] [www] r98787 - in /www/trunk/devmtg: 2007-05/index.html 2008-08-23/index.html 2008-08/index.html 2009-10/index.html index.html Message-ID: <20100318005639.D67E52A6C12C@llvm.org> Author: tbrethou Date: Wed Mar 17 19:56:39 2010 New Revision: 98787 URL: http://llvm.org/viewvc/llvm-project?rev=98787&view=rev Log: Set executable property for SSI. Modified: www/trunk/devmtg/2007-05/index.html (props changed) www/trunk/devmtg/2008-08-23/index.html (props changed) www/trunk/devmtg/2008-08/index.html (props changed) www/trunk/devmtg/2009-10/index.html (props changed) www/trunk/devmtg/index.html (props changed) Propchange: www/trunk/devmtg/2007-05/index.html ------------------------------------------------------------------------------ svn:executable = * Propchange: www/trunk/devmtg/2008-08-23/index.html ------------------------------------------------------------------------------ svn:executable = * Propchange: www/trunk/devmtg/2008-08/index.html ------------------------------------------------------------------------------ svn:executable = * Propchange: www/trunk/devmtg/2009-10/index.html ------------------------------------------------------------------------------ svn:executable = * Propchange: www/trunk/devmtg/index.html ------------------------------------------------------------------------------ svn:executable = * From daniel at zuster.org Wed Mar 17 19:58:53 2010 From: daniel at zuster.org (Daniel Dunbar) Date: Thu, 18 Mar 2010 00:58:53 -0000 Subject: [llvm-commits] [llvm] r98789 - in /llvm/trunk: include/llvm/Target/TargetAsmBackend.h lib/MC/TargetAsmBackend.cpp lib/Target/X86/X86AsmBackend.cpp Message-ID: <20100318005853.81DE42A6C12C@llvm.org> Author: ddunbar Date: Wed Mar 17 19:58:53 2010 New Revision: 98789 URL: http://llvm.org/viewvc/llvm-project?rev=98789&view=rev Log: MC/Darwin: Add a new target hook for whether the target uses "reliable" symbol differences, basically whether the assembler should attempt to understand atoms when using scattered symbols. Also, avoid some virtual call overhead. Modified: llvm/trunk/include/llvm/Target/TargetAsmBackend.h llvm/trunk/lib/MC/TargetAsmBackend.cpp llvm/trunk/lib/Target/X86/X86AsmBackend.cpp Modified: llvm/trunk/include/llvm/Target/TargetAsmBackend.h URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/Target/TargetAsmBackend.h?rev=98789&r1=98788&r2=98789&view=diff ============================================================================== --- llvm/trunk/include/llvm/Target/TargetAsmBackend.h (original) +++ llvm/trunk/include/llvm/Target/TargetAsmBackend.h Wed Mar 17 19:58:53 2010 @@ -24,6 +24,10 @@ /// TheTarget - The Target that this machine was created for. const Target &TheTarget; + unsigned HasAbsolutizedSet : 1; + unsigned HasReliableSymbolDifference : 1; + unsigned HasScatteredSymbols : 1; + public: virtual ~TargetAsmBackend(); @@ -40,7 +44,21 @@ /// value of L0 - L1. This distinction is only relevant for platforms that /// support scattered symbols, since in the absence of scattered symbols (a - /// b) cannot change after assembly. - virtual bool hasAbsolutizedSet() const { return false; } + bool hasAbsolutizedSet() const { return HasAbsolutizedSet; } + + /// hasReliableSymbolDifference - Check whether this target implements + /// accurate relocations for differences between symbols. If not, differences + /// between symbols will always be relocatable expressions and any references + /// to temporary symbols will be assumed to be in the same atom, unless they + /// reside in a different section. + /// + /// This should always be true (since it results in fewer relocations with no + /// loss of functionality), but is currently supported as a way to maintain + /// exact object compatibility with Darwin 'as' (on non-x86_64). It should + /// eventually should be eliminated. See also \see hasAbsolutizedSet. + bool hasReliableSymbolDifference() const { + return HasReliableSymbolDifference; + } /// hasScatteredSymbols - Check whether this target supports scattered /// symbols. If so, the assembler should assume that atoms can be scattered by @@ -50,7 +68,7 @@ /// /// Note that the assembler currently does not reason about atoms, instead it /// assumes all temporary symbols reside in the "current atom". - virtual bool hasScatteredSymbols() const { return false; } + bool hasScatteredSymbols() const { return HasScatteredSymbols; } /// doesSectionRequireSymbols - Check whether the given section requires that /// all symbols (even temporaries) have symbol table entries. Modified: llvm/trunk/lib/MC/TargetAsmBackend.cpp URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/MC/TargetAsmBackend.cpp?rev=98789&r1=98788&r2=98789&view=diff ============================================================================== --- llvm/trunk/lib/MC/TargetAsmBackend.cpp (original) +++ llvm/trunk/lib/MC/TargetAsmBackend.cpp Wed Mar 17 19:58:53 2010 @@ -11,7 +11,10 @@ using namespace llvm; TargetAsmBackend::TargetAsmBackend(const Target &T) - : TheTarget(T) + : TheTarget(T), + HasAbsolutizedSet(false), + HasReliableSymbolDifference(false), + HasScatteredSymbols(false) { } Modified: llvm/trunk/lib/Target/X86/X86AsmBackend.cpp URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Target/X86/X86AsmBackend.cpp?rev=98789&r1=98788&r2=98789&view=diff ============================================================================== --- llvm/trunk/lib/Target/X86/X86AsmBackend.cpp (original) +++ llvm/trunk/lib/Target/X86/X86AsmBackend.cpp Wed Mar 17 19:58:53 2010 @@ -25,11 +25,10 @@ class DarwinX86AsmBackend : public X86AsmBackend { public: DarwinX86AsmBackend(const Target &T) - : X86AsmBackend(T) {} - - virtual bool hasAbsolutizedSet() const { return true; } - - virtual bool hasScatteredSymbols() const { return true; } + : X86AsmBackend(T) { + HasAbsolutizedSet = true; + HasScatteredSymbols = true; + } }; class DarwinX86_32AsmBackend : public DarwinX86AsmBackend { @@ -41,7 +40,9 @@ class DarwinX86_64AsmBackend : public DarwinX86AsmBackend { public: DarwinX86_64AsmBackend(const Target &T) - : DarwinX86AsmBackend(T) {} + : DarwinX86AsmBackend(T) { + HasReliableSymbolDifference = true; + } virtual bool doesSectionRequireSymbols(const MCSection &Section) const { // Temporary labels in the string literals sections require symbols. The From daniel at zuster.org Wed Mar 17 19:59:03 2010 From: daniel at zuster.org (Daniel Dunbar) Date: Thu, 18 Mar 2010 00:59:03 -0000 Subject: [llvm-commits] [llvm] r98790 - /llvm/trunk/include/llvm/MC/MCSymbol.h Message-ID: <20100318005903.09B182A6C12C@llvm.org> Author: ddunbar Date: Wed Mar 17 19:59:02 2010 New Revision: 98790 URL: http://llvm.org/viewvc/llvm-project?rev=98790&view=rev Log: Add MCSymbol::isInSection. Modified: llvm/trunk/include/llvm/MC/MCSymbol.h Modified: llvm/trunk/include/llvm/MC/MCSymbol.h URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/MC/MCSymbol.h?rev=98790&r1=98789&r2=98790&view=diff ============================================================================== --- llvm/trunk/include/llvm/MC/MCSymbol.h (original) +++ llvm/trunk/include/llvm/MC/MCSymbol.h Wed Mar 17 19:59:02 2010 @@ -28,8 +28,7 @@ /// /// If the symbol is defined/emitted into the current translation unit, the /// Section member is set to indicate what section it lives in. Otherwise, if - /// it is a reference to an external entity, it has a null section. - /// + /// it is a reference to an external entity, it has a null section. class MCSymbol { // Special sentinal value for the absolute pseudo section. // @@ -52,7 +51,7 @@ /// typically does not survive in the .o file's symbol table. Usually /// "Lfoo" or ".foo". unsigned IsTemporary : 1; - + private: // MCContext creates and uniques these. friend class MCContext; MCSymbol(StringRef name, bool isTemporary) @@ -83,6 +82,12 @@ return Section != 0; } + /// isInSection - Check if this symbol is defined in some section (i.e., it + /// is defined but not absolute). + bool isInSection() const { + return isDefined() && !isAbsolute(); + } + /// isUndefined - Check if this symbol undefined (i.e., implicitly defined). bool isUndefined() const { return !isDefined(); @@ -96,7 +101,7 @@ /// getSection - Get the section associated with a defined, non-absolute /// symbol. const MCSection &getSection() const { - assert(!isUndefined() && !isAbsolute() && "Invalid accessor!"); + assert(isInSection() && "Invalid accessor!"); return *Section; } From daniel at zuster.org Wed Mar 17 19:59:10 2010 From: daniel at zuster.org (Daniel Dunbar) Date: Thu, 18 Mar 2010 00:59:10 -0000 Subject: [llvm-commits] [llvm] r98791 - in /llvm/trunk: include/llvm/MC/MCValue.h lib/MC/MCAssembler.cpp lib/MC/MCExpr.cpp lib/MC/MCValue.cpp Message-ID: <20100318005910.8B1812A6C12C@llvm.org> Author: ddunbar Date: Wed Mar 17 19:59:10 2010 New Revision: 98791 URL: http://llvm.org/viewvc/llvm-project?rev=98791&view=rev Log: MCValue: Change to holding MCSymbolRefExprs instead of MCSymbols, we will need this for accessing to symbol modifiers. Modified: llvm/trunk/include/llvm/MC/MCValue.h llvm/trunk/lib/MC/MCAssembler.cpp llvm/trunk/lib/MC/MCExpr.cpp llvm/trunk/lib/MC/MCValue.cpp Modified: llvm/trunk/include/llvm/MC/MCValue.h URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/MC/MCValue.h?rev=98791&r1=98790&r2=98791&view=diff ============================================================================== --- llvm/trunk/include/llvm/MC/MCValue.h (original) +++ llvm/trunk/include/llvm/MC/MCValue.h Wed Mar 17 19:59:10 2010 @@ -19,8 +19,9 @@ #include namespace llvm { -class MCSymbol; class MCAsmInfo; +class MCSymbol; +class MCSymbolRefExpr; class raw_ostream; /// MCValue - This represents an "assembler immediate". In its most general @@ -34,13 +35,13 @@ /// Note that this class must remain a simple POD value class, because we need /// it to live in unions etc. class MCValue { - const MCSymbol *SymA, *SymB; + const MCSymbolRefExpr *SymA, *SymB; int64_t Cst; public: int64_t getConstant() const { return Cst; } - const MCSymbol *getSymA() const { return SymA; } - const MCSymbol *getSymB() const { return SymB; } + const MCSymbolRefExpr *getSymA() const { return SymA; } + const MCSymbolRefExpr *getSymB() const { return SymB; } /// isAbsolute - Is this an absolute (as opposed to relocatable) value. bool isAbsolute() const { return !SymA && !SymB; } @@ -57,11 +58,11 @@ /// print - Print the value to the stream \arg OS. void print(raw_ostream &OS, const MCAsmInfo *MAI) const; - + /// dump - Print the value to stderr. void dump() const; - static MCValue get(const MCSymbol *SymA, const MCSymbol *SymB = 0, + static MCValue get(const MCSymbolRefExpr *SymA, const MCSymbolRefExpr *SymB=0, int64_t Val = 0) { MCValue R; assert((!SymB || SymA) && "Invalid relocatable MCValue!"); @@ -70,7 +71,7 @@ R.SymB = SymB; return R; } - + static MCValue get(int64_t Val) { MCValue R; R.Cst = Val; @@ -78,7 +79,7 @@ R.SymB = 0; return R; } - + }; } // end namespace llvm Modified: llvm/trunk/lib/MC/MCAssembler.cpp URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/MC/MCAssembler.cpp?rev=98791&r1=98790&r2=98791&view=diff ============================================================================== --- llvm/trunk/lib/MC/MCAssembler.cpp (original) +++ llvm/trunk/lib/MC/MCAssembler.cpp Wed Mar 17 19:59:10 2010 @@ -478,7 +478,7 @@ unsigned Type = RIT_Vanilla; // See . - const MCSymbol *A = Target.getSymA(); + const MCSymbol *A = &Target.getSymA()->getSymbol(); MCSymbolData *A_SD = &Asm.getSymbolData(*A); if (!A_SD->getFragment()) @@ -488,11 +488,11 @@ uint32_t Value = A_SD->getAddress(); uint32_t Value2 = 0; - if (const MCSymbol *B = Target.getSymB()) { - MCSymbolData *B_SD = &Asm.getSymbolData(*B); + if (const MCSymbolRefExpr *B = Target.getSymB()) { + MCSymbolData *B_SD = &Asm.getSymbolData(B->getSymbol()); if (!B_SD->getFragment()) - llvm_report_error("symbol '" + B->getName() + + llvm_report_error("symbol '" + B->getSymbol().getName() + "' can not be undefined in a subtraction expression"); // Select the appropriate difference relocation type. @@ -545,7 +545,7 @@ if (IsPCRel) Offset += 1 << Log2Size; if (Target.getSymB() || - (Target.getSymA() && !Target.getSymA()->isUndefined() && + (Target.getSymA() && !Target.getSymA()->getSymbol().isUndefined() && Offset)) return ComputeScatteredRelocationInfo(Asm, Fragment, Fixup, Target, Relocs); @@ -565,7 +565,7 @@ Type = RIT_Vanilla; Value = 0; } else { - const MCSymbol *Symbol = Target.getSymA(); + const MCSymbol *Symbol = &Target.getSymA()->getSymbol(); MCSymbolData *SD = &Asm.getSymbolData(*Symbol); if (Symbol->isUndefined()) { @@ -1033,28 +1033,28 @@ // atom, and so the value is resolved. We need explicit atom's to implement // this more precisely. bool IsResolved = true, IsPCRel = isFixupKindPCRel(Fixup.Kind); - if (const MCSymbol *Symbol = Target.getSymA()) { - if (Symbol->isDefined()) - Value += getSymbolData(*Symbol).getAddress(); + if (const MCSymbolRefExpr *A = Target.getSymA()) { + if (A->getSymbol().isDefined()) + Value += getSymbolData(A->getSymbol()).getAddress(); else IsResolved = false; // With scattered symbols, we assume anything that isn't a PCrel temporary // access can have an arbitrary value. if (getBackend().hasScatteredSymbols() && - (!IsPCRel || !Symbol->isTemporary())) + (!IsPCRel || !A->getSymbol().isTemporary())) IsResolved = false; } - if (const MCSymbol *Symbol = Target.getSymB()) { - if (Symbol->isDefined()) - Value -= getSymbolData(*Symbol).getAddress(); + if (const MCSymbolRefExpr *B = Target.getSymB()) { + if (B->getSymbol().isDefined()) + Value -= getSymbolData(B->getSymbol()).getAddress(); else IsResolved = false; // With scattered symbols, we assume anything that isn't a PCrel temporary // access can have an arbitrary value. if (getBackend().hasScatteredSymbols() && - (!IsPCRel || !Symbol->isTemporary())) + (!IsPCRel || !B->getSymbol().isTemporary())) IsResolved = false; } Modified: llvm/trunk/lib/MC/MCExpr.cpp URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/MC/MCExpr.cpp?rev=98791&r1=98790&r2=98791&view=diff ============================================================================== --- llvm/trunk/lib/MC/MCExpr.cpp (original) +++ llvm/trunk/lib/MC/MCExpr.cpp Wed Mar 17 19:59:10 2010 @@ -30,7 +30,7 @@ case MCExpr::SymbolRef: { const MCSymbolRefExpr &SRE = cast(*this); const MCSymbol &Sym = SRE.getSymbol(); - + // Parenthesize names that start with $ so that they don't look like // absolute names. if (Sym.getName()[0] == '$') @@ -59,14 +59,14 @@ case MCExpr::Binary: { const MCBinaryExpr &BE = cast(*this); - + // Only print parens around the LHS if it is non-trivial. if (isa(BE.getLHS()) || isa(BE.getLHS())) { OS << *BE.getLHS(); } else { OS << '(' << *BE.getLHS() << ')'; } - + switch (BE.getOpcode()) { default: assert(0 && "Invalid opcode!"); case MCBinaryExpr::Add: @@ -77,7 +77,7 @@ return; } } - + OS << '+'; break; case MCBinaryExpr::And: OS << '&'; break; @@ -98,7 +98,7 @@ case MCBinaryExpr::Sub: OS << '-'; break; case MCBinaryExpr::Xor: OS << '^'; break; } - + // Only print parens around the LHS if it is non-trivial. if (isa(BE.getRHS()) || isa(BE.getRHS())) { OS << *BE.getRHS(); @@ -193,7 +193,7 @@ bool MCExpr::EvaluateAsAbsolute(int64_t &Res, const MCAsmLayout *Layout) const { MCValue Value; - + if (!EvaluateAsRelocatable(Value, Layout) || !Value.isAbsolute()) return false; @@ -201,16 +201,16 @@ return true; } -static bool EvaluateSymbolicAdd(const MCValue &LHS, const MCSymbol *RHS_A, - const MCSymbol *RHS_B, int64_t RHS_Cst, +static bool EvaluateSymbolicAdd(const MCValue &LHS,const MCSymbolRefExpr *RHS_A, + const MCSymbolRefExpr *RHS_B, int64_t RHS_Cst, MCValue &Res) { // We can't add or subtract two symbols. if ((LHS.getSymA() && RHS_A) || (LHS.getSymB() && RHS_B)) return false; - const MCSymbol *A = LHS.getSymA() ? LHS.getSymA() : RHS_A; - const MCSymbol *B = LHS.getSymB() ? LHS.getSymB() : RHS_B; + const MCSymbolRefExpr *A = LHS.getSymA() ? LHS.getSymA() : RHS_A; + const MCSymbolRefExpr *B = LHS.getSymB() ? LHS.getSymB() : RHS_B; if (B) { // If we have a negated symbol, then we must have also have a non-negated // symbol in order to encode the expression. We can do this check later to @@ -228,13 +228,14 @@ switch (getKind()) { case Target: return cast(this)->EvaluateAsRelocatableImpl(Res, Layout); - + case Constant: Res = MCValue::get(cast(this)->getValue()); return true; case SymbolRef: { - const MCSymbol &Sym = cast(this)->getSymbol(); + const MCSymbolRefExpr *SRE = cast(this); + const MCSymbol &Sym = SRE->getSymbol(); // Evaluate recursively if this is a variable. if (Sym.isVariable()) { @@ -245,9 +246,12 @@ // layout object and the target requests it. if (Layout && Res.getSymB() && Layout->getAssembler().getBackend().hasAbsolutizedSet() && - Res.getSymA()->isDefined() && Res.getSymB()->isDefined()) { - MCSymbolData &A = Layout->getAssembler().getSymbolData(*Res.getSymA()); - MCSymbolData &B = Layout->getAssembler().getSymbolData(*Res.getSymB()); + Res.getSymA()->getSymbol().isDefined() && + Res.getSymB()->getSymbol().isDefined()) { + MCSymbolData &A = + Layout->getAssembler().getSymbolData(Res.getSymA()->getSymbol()); + MCSymbolData &B = + Layout->getAssembler().getSymbolData(Res.getSymB()->getSymbol()); Res = MCValue::get(+ A.getFragment()->getAddress() + A.getOffset() - B.getFragment()->getAddress() - B.getOffset() + Res.getConstant()); @@ -256,7 +260,7 @@ return true; } - Res = MCValue::get(&Sym, 0, 0); + Res = MCValue::get(SRE, 0, 0); return true; } @@ -277,13 +281,13 @@ /// -(a - b + const) ==> (b - a - const) if (Value.getSymA() && !Value.getSymB()) return false; - Res = MCValue::get(Value.getSymB(), Value.getSymA(), - -Value.getConstant()); + Res = MCValue::get(Value.getSymB(), Value.getSymA(), + -Value.getConstant()); break; case MCUnaryExpr::Not: if (!Value.isAbsolute()) return false; - Res = MCValue::get(~Value.getConstant()); + Res = MCValue::get(~Value.getConstant()); break; case MCUnaryExpr::Plus: Res = Value; @@ -296,7 +300,7 @@ case Binary: { const MCBinaryExpr *ABE = cast(this); MCValue LHSValue, RHSValue; - + if (!ABE->getLHS()->EvaluateAsRelocatable(LHSValue, Layout) || !ABE->getRHS()->EvaluateAsRelocatable(RHSValue, Layout)) return false; Modified: llvm/trunk/lib/MC/MCValue.cpp URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/MC/MCValue.cpp?rev=98791&r1=98790&r2=98791&view=diff ============================================================================== --- llvm/trunk/lib/MC/MCValue.cpp (original) +++ llvm/trunk/lib/MC/MCValue.cpp Wed Mar 17 19:59:10 2010 @@ -8,6 +8,7 @@ //===----------------------------------------------------------------------===// #include "llvm/MC/MCValue.h" +#include "llvm/MC/MCExpr.h" #include "llvm/Support/Debug.h" #include "llvm/Support/raw_ostream.h" @@ -19,10 +20,12 @@ return; } - OS << *getSymA(); + getSymA()->print(OS); - if (getSymB()) - OS << " - " << *getSymB(); + if (getSymB()) { + OS << " - "; + getSymB()->print(OS); + } if (getConstant()) OS << " + " << getConstant(); From daniel at zuster.org Wed Mar 17 20:00:15 2010 From: daniel at zuster.org (Daniel Dunbar) Date: Wed, 17 Mar 2010 18:00:15 -0700 Subject: [llvm-commits] [llvm] r98221 - in /llvm/trunk: include/llvm/Target/TargetAsmBackend.h lib/Target/X86/X86AsmBackend.cpp In-Reply-To: References: <20100311013422.02A942A6C12D@llvm.org> Message-ID: <6a8523d61003171800y1b6e9b11m10915657659cdd6f@mail.gmail.com> On Tue, Mar 16, 2010 at 11:42 AM, Chris Lattner wrote: > On Mar 10, 2010, at 5:34 PM, Daniel Dunbar wrote: >> URL: http://llvm.org/viewvc/llvm-project?rev=98221&view=rev >> Log: >> MC: Sketch some TargetAsmBackend hooks we are going to need. > > Hey Daniel, minor point: > >> +++ llvm/trunk/include/llvm/Target/TargetAsmBackend.h Wed Mar 10 19:34:21 2010 >> @@ -28,6 +28,28 @@ >> >> ? const Target &getTarget() const { return TheTarget; } > ... > >> >> + ?/// Note that the assembler currently does not reason about atoms, instead it >> + ?/// assumes all temporary symbols reside in the "current atom". >> + ?virtual bool hasScatteredSymbols() const { return false; } > > For properties input-free predicates like this, instead of using virtual methods, you can just have a field in the class that the subclass initializes, allowing the method to be inline. Fixed here http://llvm.org/viewvc/llvm-project?view=rev&revision=98789 - Daniel > > -Chris From andrewl at lenharth.org Wed Mar 17 20:00:31 2010 From: andrewl at lenharth.org (Andrew Lenharth) Date: Thu, 18 Mar 2010 01:00:31 -0000 Subject: [llvm-commits] [poolalloc] r98792 - in /poolalloc/trunk/lib/DSA: BottomUpClosure.cpp Local.cpp Message-ID: <20100318010031.772472A6C12C@llvm.org> Author: alenhar2 Date: Wed Mar 17 20:00:31 2010 New Revision: 98792 URL: http://llvm.org/viewvc/llvm-project?rev=98792&view=rev Log: calls sites that will never contain useful information are not added Modified: poolalloc/trunk/lib/DSA/BottomUpClosure.cpp poolalloc/trunk/lib/DSA/Local.cpp Modified: poolalloc/trunk/lib/DSA/BottomUpClosure.cpp URL: http://llvm.org/viewvc/llvm-project/poolalloc/trunk/lib/DSA/BottomUpClosure.cpp?rev=98792&r1=98791&r2=98792&view=diff ============================================================================== --- poolalloc/trunk/lib/DSA/BottomUpClosure.cpp (original) +++ poolalloc/trunk/lib/DSA/BottomUpClosure.cpp Wed Mar 17 20:00:31 2010 @@ -73,7 +73,7 @@ svset marked; for (DSCallGraph::root_iterator ii = callgraph.root_begin(), ee = callgraph.root_end(); ii != ee; ++ii) { - errs() << (*ii)->getName() << " "; + errs() << (*ii)->getName() << "\n"; DSGraph* G = postOrder(*ii, marked); CloneAuxIntoGlobal(G); } Modified: poolalloc/trunk/lib/DSA/Local.cpp URL: http://llvm.org/viewvc/llvm-project/poolalloc/trunk/lib/DSA/Local.cpp?rev=98792&r1=98791&r2=98792&view=diff ============================================================================== --- poolalloc/trunk/lib/DSA/Local.cpp (original) +++ poolalloc/trunk/lib/DSA/Local.cpp Wed Mar 17 20:00:31 2010 @@ -752,8 +752,8 @@ //Can't do much about inline asm (yet!) if (isa(CS.getCalledValue())) return; - //uninteresting call - if (!DSCallGraph::hasPointers(CS)) + //uninteresting direct call + if (CS.getCalledFunction() && !DSCallGraph::hasPointers(CS)) return; From gohman at apple.com Wed Mar 17 20:17:13 2010 From: gohman at apple.com (Dan Gohman) Date: Thu, 18 Mar 2010 01:17:13 -0000 Subject: [llvm-commits] [llvm] r98793 - in /llvm/trunk: include/llvm/Analysis/ScalarEvolutionExpressions.h lib/Analysis/ScalarEvolution.cpp lib/Analysis/ScalarEvolutionExpander.cpp Message-ID: <20100318011713.DC05F2A6C12C@llvm.org> Author: djg Date: Wed Mar 17 20:17:13 2010 New Revision: 98793 URL: http://llvm.org/viewvc/llvm-project?rev=98793&view=rev Log: Reapply r98755 with a thinko which miscompiled gengtype fixed. Modified: llvm/trunk/include/llvm/Analysis/ScalarEvolutionExpressions.h llvm/trunk/lib/Analysis/ScalarEvolution.cpp llvm/trunk/lib/Analysis/ScalarEvolutionExpander.cpp Modified: llvm/trunk/include/llvm/Analysis/ScalarEvolutionExpressions.h URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/Analysis/ScalarEvolutionExpressions.h?rev=98793&r1=98792&r2=98793&view=diff ============================================================================== --- llvm/trunk/include/llvm/Analysis/ScalarEvolutionExpressions.h (original) +++ llvm/trunk/include/llvm/Analysis/ScalarEvolutionExpressions.h Wed Mar 17 20:17:13 2010 @@ -180,25 +180,27 @@ /// class SCEVNAryExpr : public SCEV { protected: - SmallVector Operands; + // Since SCEVs are immutable, ScalarEvolution allocates operand + // arrays with its SCEVAllocator, so this class just needs a simple + // pointer rather than a more elaborate vector-like data structure. + // This also avoids the need for a non-trivial destructor. + const SCEV *const *Operands; + size_t NumOperands; SCEVNAryExpr(const FoldingSetNodeID &ID, - enum SCEVTypes T, const SmallVectorImpl &ops) - : SCEV(ID, T), Operands(ops.begin(), ops.end()) {} + enum SCEVTypes T, const SCEV *const *O, size_t N) + : SCEV(ID, T), Operands(O), NumOperands(N) {} public: - unsigned getNumOperands() const { return (unsigned)Operands.size(); } + size_t getNumOperands() const { return NumOperands; } const SCEV *getOperand(unsigned i) const { - assert(i < Operands.size() && "Operand index out of range!"); + assert(i < NumOperands && "Operand index out of range!"); return Operands[i]; } - const SmallVectorImpl &getOperands() const { - return Operands; - } - typedef SmallVectorImpl::const_iterator op_iterator; - op_iterator op_begin() const { return Operands.begin(); } - op_iterator op_end() const { return Operands.end(); } + typedef const SCEV *const *op_iterator; + op_iterator op_begin() const { return Operands; } + op_iterator op_end() const { return Operands + NumOperands; } virtual bool isLoopInvariant(const Loop *L) const { for (unsigned i = 0, e = getNumOperands(); i != e; ++i) @@ -262,8 +264,8 @@ protected: SCEVCommutativeExpr(const FoldingSetNodeID &ID, enum SCEVTypes T, - const SmallVectorImpl &ops) - : SCEVNAryExpr(ID, T, ops) {} + const SCEV *const *O, size_t N) + : SCEVNAryExpr(ID, T, O, N) {} public: virtual const char *getOperationStr() const = 0; @@ -288,8 +290,8 @@ friend class ScalarEvolution; SCEVAddExpr(const FoldingSetNodeID &ID, - const SmallVectorImpl &ops) - : SCEVCommutativeExpr(ID, scAddExpr, ops) { + const SCEV *const *O, size_t N) + : SCEVCommutativeExpr(ID, scAddExpr, O, N) { } public: @@ -316,8 +318,8 @@ friend class ScalarEvolution; SCEVMulExpr(const FoldingSetNodeID &ID, - const SmallVectorImpl &ops) - : SCEVCommutativeExpr(ID, scMulExpr, ops) { + const SCEV *const *O, size_t N) + : SCEVCommutativeExpr(ID, scMulExpr, O, N) { } public: @@ -390,9 +392,9 @@ const Loop *L; SCEVAddRecExpr(const FoldingSetNodeID &ID, - const SmallVectorImpl &ops, const Loop *l) - : SCEVNAryExpr(ID, scAddRecExpr, ops), L(l) { - for (size_t i = 0, e = Operands.size(); i != e; ++i) + const SCEV *const *O, size_t N, const Loop *l) + : SCEVNAryExpr(ID, scAddRecExpr, O, N), L(l) { + for (size_t i = 0, e = NumOperands; i != e; ++i) assert(Operands[i]->isLoopInvariant(l) && "Operands of AddRec must be loop-invariant!"); } @@ -472,8 +474,8 @@ friend class ScalarEvolution; SCEVSMaxExpr(const FoldingSetNodeID &ID, - const SmallVectorImpl &ops) - : SCEVCommutativeExpr(ID, scSMaxExpr, ops) { + const SCEV *const *O, size_t N) + : SCEVCommutativeExpr(ID, scSMaxExpr, O, N) { // Max never overflows. setHasNoUnsignedWrap(true); setHasNoSignedWrap(true); @@ -497,8 +499,8 @@ friend class ScalarEvolution; SCEVUMaxExpr(const FoldingSetNodeID &ID, - const SmallVectorImpl &ops) - : SCEVCommutativeExpr(ID, scUMaxExpr, ops) { + const SCEV *const *O, size_t N) + : SCEVCommutativeExpr(ID, scUMaxExpr, O, N) { // Max never overflows. setHasNoUnsignedWrap(true); setHasNoSignedWrap(true); Modified: llvm/trunk/lib/Analysis/ScalarEvolution.cpp URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Analysis/ScalarEvolution.cpp?rev=98793&r1=98792&r2=98793&view=diff ============================================================================== --- llvm/trunk/lib/Analysis/ScalarEvolution.cpp (original) +++ llvm/trunk/lib/Analysis/ScalarEvolution.cpp Wed Mar 17 20:17:13 2010 @@ -248,10 +248,10 @@ } void SCEVCommutativeExpr::print(raw_ostream &OS) const { - assert(Operands.size() > 1 && "This plus expr shouldn't exist!"); + assert(NumOperands > 1 && "This plus expr shouldn't exist!"); const char *OpStr = getOperationStr(); OS << "(" << *Operands[0]; - for (unsigned i = 1, e = Operands.size(); i != e; ++i) + for (unsigned i = 1, e = NumOperands; i != e; ++i) OS << OpStr << *Operands[i]; OS << ")"; } @@ -329,7 +329,7 @@ void SCEVAddRecExpr::print(raw_ostream &OS) const { OS << "{" << *Operands[0]; - for (unsigned i = 1, e = Operands.size(); i != e; ++i) + for (unsigned i = 1, e = NumOperands; i != e; ++i) OS << ",+," << *Operands[i]; OS << "}<"; WriteAsOperand(OS, L->getHeader(), /*PrintType=*/false); @@ -1202,23 +1202,23 @@ CollectAddOperandsWithScales(DenseMap &M, SmallVector &NewOps, APInt &AccumulatedConstant, - const SmallVectorImpl &Ops, + const SCEV *const *Ops, size_t NumOperands, const APInt &Scale, ScalarEvolution &SE) { bool Interesting = false; // Iterate over the add operands. - for (unsigned i = 0, e = Ops.size(); i != e; ++i) { + for (unsigned i = 0, e = NumOperands; i != e; ++i) { const SCEVMulExpr *Mul = dyn_cast(Ops[i]); if (Mul && isa(Mul->getOperand(0))) { APInt NewScale = Scale * cast(Mul->getOperand(0))->getValue()->getValue(); if (Mul->getNumOperands() == 2 && isa(Mul->getOperand(1))) { // A multiplication of a constant with another add; recurse. + const SCEVAddExpr *Add = cast(Mul->getOperand(1)); Interesting |= CollectAddOperandsWithScales(M, NewOps, AccumulatedConstant, - cast(Mul->getOperand(1)) - ->getOperands(), + Add->op_begin(), Add->getNumOperands(), NewScale, SE); } else { // A multiplication of a constant with some other value. Update @@ -1427,7 +1427,8 @@ SmallVector NewOps; APInt AccumulatedConstant(BitWidth, 0); if (CollectAddOperandsWithScales(M, NewOps, AccumulatedConstant, - Ops, APInt(BitWidth, 1), *this)) { + Ops.data(), Ops.size(), + APInt(BitWidth, 1), *this)) { // Some interesting folding opportunity is present, so its worthwhile to // re-generate the operands list. Group the operands by constant scale, // to avoid multiplying by the same constant scale multiple times. @@ -1612,7 +1613,9 @@ static_cast(UniqueSCEVs.FindNodeOrInsertPos(ID, IP)); if (!S) { S = SCEVAllocator.Allocate(); - new (S) SCEVAddExpr(ID, Ops); + const SCEV **O = SCEVAllocator.Allocate(Ops.size()); + std::uninitialized_copy(Ops.begin(), Ops.end(), O); + new (S) SCEVAddExpr(ID, O, Ops.size()); UniqueSCEVs.InsertNode(S, IP); } if (HasNUW) S->setHasNoUnsignedWrap(true); @@ -1820,7 +1823,9 @@ static_cast(UniqueSCEVs.FindNodeOrInsertPos(ID, IP)); if (!S) { S = SCEVAllocator.Allocate(); - new (S) SCEVMulExpr(ID, Ops); + const SCEV **O = SCEVAllocator.Allocate(Ops.size()); + std::uninitialized_copy(Ops.begin(), Ops.end(), O); + new (S) SCEVMulExpr(ID, O, Ops.size()); UniqueSCEVs.InsertNode(S, IP); } if (HasNUW) S->setHasNoUnsignedWrap(true); @@ -1880,9 +1885,7 @@ const SCEV *Op = M->getOperand(i); const SCEV *Div = getUDivExpr(Op, RHSC); if (!isa(Div) && getMulExpr(Div, RHSC) == Op) { - const SmallVectorImpl &MOperands = M->getOperands(); - Operands = SmallVector(MOperands.begin(), - MOperands.end()); + Operands = SmallVector(M->op_begin(), M->op_end()); Operands[i] = Div; return getMulExpr(Operands); } @@ -2031,7 +2034,9 @@ static_cast(UniqueSCEVs.FindNodeOrInsertPos(ID, IP)); if (!S) { S = SCEVAllocator.Allocate(); - new (S) SCEVAddRecExpr(ID, Operands, L); + const SCEV **O = SCEVAllocator.Allocate(Operands.size()); + std::uninitialized_copy(Operands.begin(), Operands.end(), O); + new (S) SCEVAddRecExpr(ID, O, Operands.size(), L); UniqueSCEVs.InsertNode(S, IP); } if (HasNUW) S->setHasNoUnsignedWrap(true); @@ -2131,7 +2136,9 @@ void *IP = 0; if (const SCEV *S = UniqueSCEVs.FindNodeOrInsertPos(ID, IP)) return S; SCEV *S = SCEVAllocator.Allocate(); - new (S) SCEVSMaxExpr(ID, Ops); + const SCEV **O = SCEVAllocator.Allocate(Ops.size()); + std::uninitialized_copy(Ops.begin(), Ops.end(), O); + new (S) SCEVSMaxExpr(ID, O, Ops.size()); UniqueSCEVs.InsertNode(S, IP); return S; } @@ -2228,7 +2235,9 @@ void *IP = 0; if (const SCEV *S = UniqueSCEVs.FindNodeOrInsertPos(ID, IP)) return S; SCEV *S = SCEVAllocator.Allocate(); - new (S) SCEVUMaxExpr(ID, Ops); + const SCEV **O = SCEVAllocator.Allocate(Ops.size()); + std::uninitialized_copy(Ops.begin(), Ops.end(), O); + new (S) SCEVUMaxExpr(ID, O, Ops.size()); UniqueSCEVs.InsertNode(S, IP); return S; } Modified: llvm/trunk/lib/Analysis/ScalarEvolutionExpander.cpp URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Analysis/ScalarEvolutionExpander.cpp?rev=98793&r1=98792&r2=98793&view=diff ============================================================================== --- llvm/trunk/lib/Analysis/ScalarEvolutionExpander.cpp (original) +++ llvm/trunk/lib/Analysis/ScalarEvolutionExpander.cpp Wed Mar 17 20:17:13 2010 @@ -232,9 +232,7 @@ const SCEVConstant *FC = cast(Factor); if (const SCEVConstant *C = dyn_cast(M->getOperand(0))) if (!C->getValue()->getValue().srem(FC->getValue()->getValue())) { - const SmallVectorImpl &MOperands = M->getOperands(); - SmallVector NewMulOps(MOperands.begin(), - MOperands.end()); + SmallVector NewMulOps(M->op_begin(), M->op_end()); NewMulOps[0] = SE.getConstant(C->getValue()->getValue().sdiv( FC->getValue()->getValue())); @@ -249,9 +247,7 @@ const SCEV *Remainder = SE.getIntegerSCEV(0, SOp->getType()); if (FactorOutConstant(SOp, Remainder, Factor, SE, TD) && Remainder->isZero()) { - const SmallVectorImpl &MOperands = M->getOperands(); - SmallVector NewMulOps(MOperands.begin(), - MOperands.end()); + SmallVector NewMulOps(M->op_begin(), M->op_end()); NewMulOps[i] = SOp; S = SE.getMulExpr(NewMulOps); return true; @@ -297,13 +293,11 @@ SE.getAddExpr(NoAddRecs); // If it returned an add, use the operands. Otherwise it simplified // the sum into a single value, so just use that. + Ops.clear(); if (const SCEVAddExpr *Add = dyn_cast(Sum)) - Ops = Add->getOperands(); - else { - Ops.clear(); - if (!Sum->isZero()) - Ops.push_back(Sum); - } + Ops.insert(Ops.end(), Add->op_begin(), Add->op_end()); + else if (!Sum->isZero()) + Ops.push_back(Sum); // Then append the addrecs. Ops.insert(Ops.end(), AddRecs.begin(), AddRecs.end()); } @@ -1060,10 +1054,9 @@ if (CanonicalIV && SE.getTypeSizeInBits(CanonicalIV->getType()) > SE.getTypeSizeInBits(Ty)) { - const SmallVectorImpl &Ops = S->getOperands(); - SmallVector NewOps(Ops.size()); - for (unsigned i = 0, e = Ops.size(); i != e; ++i) - NewOps[i] = SE.getAnyExtendExpr(Ops[i], CanonicalIV->getType()); + SmallVector NewOps(S->getNumOperands()); + for (unsigned i = 0, e = S->getNumOperands(); i != e; ++i) + NewOps[i] = SE.getAnyExtendExpr(S->op_begin()[i], CanonicalIV->getType()); Value *V = expand(SE.getAddRecExpr(NewOps, S->getLoop())); BasicBlock *SaveInsertBB = Builder.GetInsertBlock(); BasicBlock::iterator SaveInsertPt = Builder.GetInsertPoint(); @@ -1078,8 +1071,7 @@ // {X,+,F} --> X + {0,+,F} if (!S->getStart()->isZero()) { - const SmallVectorImpl &SOperands = S->getOperands(); - SmallVector NewOps(SOperands.begin(), SOperands.end()); + SmallVector NewOps(S->op_begin(), S->op_end()); NewOps[0] = SE.getIntegerSCEV(0, Ty); const SCEV *Rest = SE.getAddRecExpr(NewOps, L); From xuzhongxing at gmail.com Wed Mar 17 21:49:16 2010 From: xuzhongxing at gmail.com (Zhongxing Xu) Date: Thu, 18 Mar 2010 10:49:16 +0800 Subject: [llvm-commits] [patch] Tautology? Message-ID: <5400aeb81003171949j335ceae8y2ef48ef5b169ab26@mail.gmail.com> Index: utils/TableGen/Record.cpp =================================================================== --- utils/TableGen/Record.cpp (?? 98703) +++ utils/TableGen/Record.cpp (????) @@ -644,20 +644,6 @@ DagInit *LHSs = dynamic_cast(LHS); DagInit *RHSs = dynamic_cast(RHS); if (LHSs && RHSs) { - DefInit *LOp = dynamic_cast(LHSs->getOperator()); - DefInit *ROp = dynamic_cast(RHSs->getOperator()); - if (LOp->getDef() != ROp->getDef()) { - bool LIsOps = - LOp->getDef()->getName() == "outs" || - LOp->getDef()->getName() != "ins" || - LOp->getDef()->getName() != "defs"; - bool RIsOps = - ROp->getDef()->getName() == "outs" || - ROp->getDef()->getName() != "ins" || - ROp->getDef()->getName() != "defs"; - if (!LIsOps || !RIsOps) - throw "Concated Dag operators do not match!"; - } std::vector Args; std::vector ArgNames; for (unsigned i = 0, e = LHSs->getNumArgs(); i != e; ++i) { LOp->getDef()->getName() != "ins" || LOp->getDef()->getName() != "defs"; will always be true. -------------- next part -------------- An HTML attachment was scrubbed... URL: http://lists.cs.uiuc.edu/pipermail/llvm-commits/attachments/20100318/b99874c8/attachment.html From clattner at apple.com Thu Mar 18 01:00:59 2010 From: clattner at apple.com (Chris Lattner) Date: Wed, 17 Mar 2010 23:00:59 -0700 Subject: [llvm-commits] [patch] Tautology? In-Reply-To: <5400aeb81003171949j335ceae8y2ef48ef5b169ab26@mail.gmail.com> References: <5400aeb81003171949j335ceae8y2ef48ef5b169ab26@mail.gmail.com> Message-ID: <9C5E1FE4-0F24-473C-A797-4A4EFF9F6A12@apple.com> Yeah, that is weird. Evan, you added this in r40033, do you happen to know what you meant here? -Chris On Mar 17, 2010, at 7:49 PM, Zhongxing Xu wrote: > Index: utils/TableGen/Record.cpp > =================================================================== > --- utils/TableGen/Record.cpp (?? 98703) > +++ utils/TableGen/Record.cpp (????) > @@ -644,20 +644,6 @@ > DagInit *LHSs = dynamic_cast(LHS); > DagInit *RHSs = dynamic_cast(RHS); > if (LHSs && RHSs) { > - DefInit *LOp = dynamic_cast(LHSs->getOperator()); > - DefInit *ROp = dynamic_cast(RHSs->getOperator()); > - if (LOp->getDef() != ROp->getDef()) { > - bool LIsOps = > - LOp->getDef()->getName() == "outs" || > - LOp->getDef()->getName() != "ins" || > - LOp->getDef()->getName() != "defs"; > - bool RIsOps = > - ROp->getDef()->getName() == "outs" || > - ROp->getDef()->getName() != "ins" || > - ROp->getDef()->getName() != "defs"; > - if (!LIsOps || !RIsOps) > - throw "Concated Dag operators do not match!"; > - } > std::vector Args; > std::vector ArgNames; > for (unsigned i = 0, e = LHSs->getNumArgs(); i != e; ++i) { > > > LOp->getDef()->getName() != "ins" || LOp->getDef()->getName() != "defs"; > will always be true. > _______________________________________________ > llvm-commits mailing list > llvm-commits at cs.uiuc.edu > http://lists.cs.uiuc.edu/mailman/listinfo/llvm-commits From resistor at mac.com Thu Mar 18 01:06:24 2010 From: resistor at mac.com (Owen Anderson) Date: Thu, 18 Mar 2010 06:06:24 -0000 Subject: [llvm-commits] [www-pubs] r98802 - in /www-pubs/trunk: 2010-03-ASPLOS-SpeculativeParallelization.html 2010-03-ASPLOS-SpeculativeParallelization.pdf pubs.js Message-ID: <20100318060624.2ADD72A6C12C@llvm.org> Author: resistor Date: Thu Mar 18 01:06:23 2010 New Revision: 98802 URL: http://llvm.org/viewvc/llvm-project?rev=98802&view=rev Log: Add a paper from this year's ASPLOS. Added: www-pubs/trunk/2010-03-ASPLOS-SpeculativeParallelization.html www-pubs/trunk/2010-03-ASPLOS-SpeculativeParallelization.pdf (with props) Modified: www-pubs/trunk/pubs.js Added: www-pubs/trunk/2010-03-ASPLOS-SpeculativeParallelization.html URL: http://llvm.org/viewvc/llvm-project/www-pubs/trunk/2010-03-ASPLOS-SpeculativeParallelization.html?rev=98802&view=auto ============================================================================== --- www-pubs/trunk/2010-03-ASPLOS-SpeculativeParallelization.html (added) +++ www-pubs/trunk/2010-03-ASPLOS-SpeculativeParallelization.html Thu Mar 18 01:06:23 2010 @@ -0,0 +1,49 @@ + + + + + + Speculative Parallelization using Software Multi-Threaded Transactions + + + +
        + Speculative Parallelization using Software Multi-Threaded Transactions +
        +
        + Arun Raman, Hanjun Kim, Thomas R. Mason, Thomas B. Jablin, David I. August +
        + +

        Abstract:

        +
        +

        The behavior of a multithreaded program does not depend only on its inputs. Scheduling, memory reordering, timing, and low-level hardware effects all introduce nondeterminism in the execution of multithreaded programs. This severely complicates many tasks, including debugging, testing, and automatic replication. In this work, we avoid these complications by eliminating their root cause: we develop a compiler and runtime system that runs arbitrary multithreaded C/C++ POSIX Threads programs deterministically.

        + +

        A trivial non-performant approach to providing determinism is simply deterministically serializing execution. Instead, we present a compiler and runtime infrastructure that ensures determinism but resorts to serialization rarely, for handling interthread communication and synchronization. We develop two basic approaches, both of which are largely dynamic with performance improved by some static compiler optimizations. First, an ownership-based approach detects interthread communication via an evolving table that tracks ownership of memory regions by threads. Second, a buffering approach uses versioned memory and employs a deterministic commit protocol to make changes visible to other threads. While buffering has larger single-threaded overhead than ownership, it tends to scale better (serializing less often). A hybrid system sometimes performs and scales better than either approach individually.

        +
        + +

        Published:

        +
        + "Speculative Parallelization using Software Multi-Threaded Transactions" +
        + Arun Raman, Hanjun Kim, Thomas R. Mason, Thomas B. Jablin, David I. August. +
        + +Proc. of the 15th international conference on Architectural Support for Programming Languages and Operating Systems, Pittsburgh, PA, March 2010. +
        +

        Download:

        +

        Paper:

        + + + +
        + Valid CSS! + Valid HTML 4.01! + + + Added: www-pubs/trunk/2010-03-ASPLOS-SpeculativeParallelization.pdf URL: http://llvm.org/viewvc/llvm-project/www-pubs/trunk/2010-03-ASPLOS-SpeculativeParallelization.pdf?rev=98802&view=auto ============================================================================== Binary file - no diff available. Propchange: www-pubs/trunk/2010-03-ASPLOS-SpeculativeParallelization.pdf ------------------------------------------------------------------------------ svn:mime-type = application/octet-stream Modified: www-pubs/trunk/pubs.js URL: http://llvm.org/viewvc/llvm-project/www-pubs/trunk/pubs.js?rev=98802&r1=98801&r2=98802&view=diff ============================================================================== --- www-pubs/trunk/pubs.js (original) +++ www-pubs/trunk/pubs.js Thu Mar 18 01:06:23 2010 @@ -1,12 +1,19 @@ // The array should be sorted reverse-chronologically, and will be displayed on // the page in the order listed. var PUBS = [ + {url: "2010-03-ASPLOS-SpeculativeParallelization.html", + title: "Speculative Parallelization using Software Multi-Threaded Transactions", + published: "Proc. of the Fifteenth International Conference on Architectural Support for Programming Languages and Operating Systems (ASPLOS '10)", + author: "Arun Raman, Hanjun Kim, Thomas R. Mason, Thomas B. Jablin, David I. August", + location: "Pittsburgh, PA", + month: 3, + year: 2010}, {url: "2010-04-ASPLOS-DeterministicCompiler.html", title: "CoreDet: A Compiler and Runtime System for Deterministic Multithreaded Execution", published: "Proc. of the Fifteenth International Conference on Architectural Support for Programming Languages and Operating Systems (ASPLOS '10)", author: "Tom Bergan, Owen Anderson, Joseph Devietti, Luis Ceze, and Dan Grossman", location: "Pittsburgh, PA", - month: 4, + month: 3, year: 2010}, {url: "2010-01-Wennborg-Thesis.html", From resistor at mac.com Thu Mar 18 01:09:51 2010 From: resistor at mac.com (Owen Anderson) Date: Thu, 18 Mar 2010 06:09:51 -0000 Subject: [llvm-commits] [www-pubs] r98803 - /www-pubs/trunk/2010-03-ASPLOS-SpeculativeParallelization.html Message-ID: <20100318060951.4F3062A6C12C@llvm.org> Author: resistor Date: Thu Mar 18 01:09:51 2010 New Revision: 98803 URL: http://llvm.org/viewvc/llvm-project?rev=98803&view=rev Log: Copy and paste fail. :-( Modified: www-pubs/trunk/2010-03-ASPLOS-SpeculativeParallelization.html Modified: www-pubs/trunk/2010-03-ASPLOS-SpeculativeParallelization.html URL: http://llvm.org/viewvc/llvm-project/www-pubs/trunk/2010-03-ASPLOS-SpeculativeParallelization.html?rev=98803&r1=98802&r2=98803&view=diff ============================================================================== --- www-pubs/trunk/2010-03-ASPLOS-SpeculativeParallelization.html (original) +++ www-pubs/trunk/2010-03-ASPLOS-SpeculativeParallelization.html Thu Mar 18 01:09:51 2010 @@ -16,9 +16,7 @@

        Abstract:

        -

        The behavior of a multithreaded program does not depend only on its inputs. Scheduling, memory reordering, timing, and low-level hardware effects all introduce nondeterminism in the execution of multithreaded programs. This severely complicates many tasks, including debugging, testing, and automatic replication. In this work, we avoid these complications by eliminating their root cause: we develop a compiler and runtime system that runs arbitrary multithreaded C/C++ POSIX Threads programs deterministically.

        - -

        A trivial non-performant approach to providing determinism is simply deterministically serializing execution. Instead, we present a compiler and runtime infrastructure that ensures determinism but resorts to serialization rarely, for handling interthread communication and synchronization. We develop two basic approaches, both of which are largely dynamic with performance improved by some static compiler optimizations. First, an ownership-based approach detects interthread communication via an evolving table that tracks ownership of memory regions by threads. Second, a buffering approach uses versioned memory and employs a deterministic commit protocol to make changes visible to other threads. While buffering has larger single-threaded overhead than ownership, it tends to scale better (serializing less often). A hybrid system sometimes performs and scales better than either approach individually.

        +

        With the right techniques, multicore architectures may be able to continue the exponential performance trend that elevated the performance of applications of all types for decades. While many scientific programs can be parallelized without speculative techniques, speculative parallelism appears to be the key to continuing this trend for general-purpose applications. Recently-proposed code parallelization techniques, such as those by Bridges et al. and by Thies et al., demonstrate scalable performance on multiple cores by using speculation to divide code into atomic units (transactions) that span multiple threads in order to expose data parallelism. Unfortunately, most software and hardware Thread-Level Speculation (TLS) memory systems and transactional memories are not sufficient because they only support single-threaded atomic units. Multi-threaded Transactions (MTXs) address this problem, but they require expensive hardware support as currently proposed in the literatur e. This paper proposes a Software MTX (SMTX) system that captures the applicability and performance of hardware MTX, but on existing multicore machines. The SMTX system yields a harmonic mean speedup of 13.36x on native hardware with four 6-core processors (24 cores in total) running speculatively parallelized applications.

        Published:

        From evan.cheng at apple.com Thu Mar 18 01:16:29 2010 From: evan.cheng at apple.com (Evan Cheng) Date: Wed, 17 Mar 2010 23:16:29 -0700 Subject: [llvm-commits] [patch] Tautology? In-Reply-To: <9C5E1FE4-0F24-473C-A797-4A4EFF9F6A12@apple.com> References: <5400aeb81003171949j335ceae8y2ef48ef5b169ab26@mail.gmail.com> <9C5E1FE4-0F24-473C-A797-4A4EFF9F6A12@apple.com> Message-ID: <4C86B10C-5925-44EA-978A-E564F4710B6F@apple.com> On Mar 17, 2010, at 11:00 PM, Chris Lattner wrote: > Yeah, that is weird. Evan, you added this in r40033, do you happen to know what you meant here? No. I am blanking. Looks like copy-n-paste bug. I think all the != should be ==? Evan > > -Chris > > On Mar 17, 2010, at 7:49 PM, Zhongxing Xu wrote: > >> Index: utils/TableGen/Record.cpp >> =================================================================== >> --- utils/TableGen/Record.cpp (?? 98703) >> +++ utils/TableGen/Record.cpp (????) >> @@ -644,20 +644,6 @@ >> DagInit *LHSs = dynamic_cast(LHS); >> DagInit *RHSs = dynamic_cast(RHS); >> if (LHSs && RHSs) { >> - DefInit *LOp = dynamic_cast(LHSs->getOperator()); >> - DefInit *ROp = dynamic_cast(RHSs->getOperator()); >> - if (LOp->getDef() != ROp->getDef()) { >> - bool LIsOps = >> - LOp->getDef()->getName() == "outs" || >> - LOp->getDef()->getName() != "ins" || >> - LOp->getDef()->getName() != "defs"; >> - bool RIsOps = >> - ROp->getDef()->getName() == "outs" || >> - ROp->getDef()->getName() != "ins" || >> - ROp->getDef()->getName() != "defs"; >> - if (!LIsOps || !RIsOps) >> - throw "Concated Dag operators do not match!"; >> - } >> std::vector Args; >> std::vector ArgNames; >> for (unsigned i = 0, e = LHSs->getNumArgs(); i != e; ++i) { >> >> >> LOp->getDef()->getName() != "ins" || LOp->getDef()->getName() != "defs"; >> will always be true. >> _______________________________________________ >> llvm-commits mailing list >> llvm-commits at cs.uiuc.edu >> http://lists.cs.uiuc.edu/mailman/listinfo/llvm-commits > From clattner at apple.com Thu Mar 18 01:20:15 2010 From: clattner at apple.com (Chris Lattner) Date: Wed, 17 Mar 2010 23:20:15 -0700 Subject: [llvm-commits] [patch] Tautology? In-Reply-To: <4C86B10C-5925-44EA-978A-E564F4710B6F@apple.com> References: <5400aeb81003171949j335ceae8y2ef48ef5b169ab26@mail.gmail.com> <9C5E1FE4-0F24-473C-A797-4A4EFF9F6A12@apple.com> <4C86B10C-5925-44EA-978A-E564F4710B6F@apple.com> Message-ID: <64DCF242-2247-4159-A2C3-2CF5DEBB0420@apple.com> On Mar 17, 2010, at 11:16 PM, Evan Cheng wrote: > > On Mar 17, 2010, at 11:00 PM, Chris Lattner wrote: > >> Yeah, that is weird. Evan, you added this in r40033, do you happen to know what you meant here? > > No. I am blanking. Looks like copy-n-paste bug. I think all the != should be ==? No idea! Please make whatever fix you think is right, optionally just removing the code as dead. -Chris > > Evan > >> >> -Chris >> >> On Mar 17, 2010, at 7:49 PM, Zhongxing Xu wrote: >> >>> Index: utils/TableGen/Record.cpp >>> =================================================================== >>> --- utils/TableGen/Record.cpp (?? 98703) >>> +++ utils/TableGen/Record.cpp (????) >>> @@ -644,20 +644,6 @@ >>> DagInit *LHSs = dynamic_cast(LHS); >>> DagInit *RHSs = dynamic_cast(RHS); >>> if (LHSs && RHSs) { >>> - DefInit *LOp = dynamic_cast(LHSs->getOperator()); >>> - DefInit *ROp = dynamic_cast(RHSs->getOperator()); >>> - if (LOp->getDef() != ROp->getDef()) { >>> - bool LIsOps = >>> - LOp->getDef()->getName() == "outs" || >>> - LOp->getDef()->getName() != "ins" || >>> - LOp->getDef()->getName() != "defs"; >>> - bool RIsOps = >>> - ROp->getDef()->getName() == "outs" || >>> - ROp->getDef()->getName() != "ins" || >>> - ROp->getDef()->getName() != "defs"; >>> - if (!LIsOps || !RIsOps) >>> - throw "Concated Dag operators do not match!"; >>> - } >>> std::vector Args; >>> std::vector ArgNames; >>> for (unsigned i = 0, e = LHSs->getNumArgs(); i != e; ++i) { >>> >>> >>> LOp->getDef()->getName() != "ins" || LOp->getDef()->getName() != "defs"; >>> will always be true. >>> _______________________________________________ >>> llvm-commits mailing list >>> llvm-commits at cs.uiuc.edu >>> http://lists.cs.uiuc.edu/mailman/listinfo/llvm-commits >> > From resistor at mac.com Thu Mar 18 01:22:35 2010 From: resistor at mac.com (Owen Anderson) Date: Thu, 18 Mar 2010 06:22:35 -0000 Subject: [llvm-commits] [www-pubs] r98804 - in /www-pubs/trunk: 2010-03-ASPLOS-ConservationCores.html 2010-03-ASPLOS-ConservationCores.pdf 2010-03-ASPLOS-Orthrus.html 2010-03-ASPLOS-Orthrus.pdf 2010-03-ASPLOS-Shoestring.html 2010-03-ASPLOS-Shoestring.pdf pubs.js Message-ID: <20100318062235.DB68C2A6C12C@llvm.org> Author: resistor Date: Thu Mar 18 01:22:35 2010 New Revision: 98804 URL: http://llvm.org/viewvc/llvm-project?rev=98804&view=rev Log: Add the remaining papers from ASPLOS. Added: www-pubs/trunk/2010-03-ASPLOS-ConservationCores.html www-pubs/trunk/2010-03-ASPLOS-ConservationCores.pdf (with props) www-pubs/trunk/2010-03-ASPLOS-Orthrus.html www-pubs/trunk/2010-03-ASPLOS-Orthrus.pdf www-pubs/trunk/2010-03-ASPLOS-Shoestring.html www-pubs/trunk/2010-03-ASPLOS-Shoestring.pdf Modified: www-pubs/trunk/pubs.js Added: www-pubs/trunk/2010-03-ASPLOS-ConservationCores.html URL: http://llvm.org/viewvc/llvm-project/www-pubs/trunk/2010-03-ASPLOS-ConservationCores.html?rev=98804&view=auto ============================================================================== --- www-pubs/trunk/2010-03-ASPLOS-ConservationCores.html (added) +++ www-pubs/trunk/2010-03-ASPLOS-ConservationCores.html Thu Mar 18 01:22:35 2010 @@ -0,0 +1,47 @@ + + + + + + Conservation Cores: Reducing the Energy of Mature Computations + + + +
        + Conservation Cores: Reducing the Energy of Mature Computations +
        +
        + Ganesh Venkatesh, Jack Sampson, Nathan Goulding, Saturnino Garcia, Vladyslav Bryksin, Jose Lugo-Martinez, Steven Swanson, Michael Bedford Taylor +
        + +

        Abstract:

        +
        +

        Growing transistor counts, limited power budgets, and the breakdown of voltage scaling are currently conspiring to create a utilization wall that limits the fraction of a chip that can run at full speed at one time. In this regime, specialized, energy-efficient processors can increase parallelism by reducing the per-computation power requirements and allowing more computations to execute under the same power budget. To pursue this goal, this paper introduces conservation cores. Conservation cores, or c-cores, are specialized processors that focus on reducing energy and energy-delay instead of increasing performance. This focus on energy makes c-cores an excellent match for many applications that would be poor candidates for hardware acceleration (e.g., irregular integer codes). We present a toolchain for automatically synthesizing c-cores from application source code and demonstrate that they can significantly reduce energy and energy-delay for a wide range of application s. The c-cores support patching, a form of targeted reconfigurability, that allows them to adapt to new versions of the software they target. Our results show that conservation cores can reduce energy consumption by up to 16.0x for functions and by up to 2.1x for whole applications, while patching can extend the useful lifetime of individual c-cores to match that of conventional processors.

        +
        + +

        Published:

        +
        + "Conservation Cores: Reducing the Energy of Mature Computations" +
        + Ganesh Venkatesh, Jack Sampson, Nathan Goulding, Saturnino Garcia, Vladyslav Bryksin, Jose Lugo-Martinez, Steven Swanson, Michael Bedford Taylor +
        + +Proc. of the 15th international conference on Architectural Support for Programming Languages and Operating Systems, Pittsburgh, PA, March 2010. +
        +

        Download:

        +

        Paper:

        + + + +
        + Valid CSS! + Valid HTML 4.01! + + + Added: www-pubs/trunk/2010-03-ASPLOS-ConservationCores.pdf URL: http://llvm.org/viewvc/llvm-project/www-pubs/trunk/2010-03-ASPLOS-ConservationCores.pdf?rev=98804&view=auto ============================================================================== Binary file - no diff available. Propchange: www-pubs/trunk/2010-03-ASPLOS-ConservationCores.pdf ------------------------------------------------------------------------------ svn:mime-type = application/octet-stream Added: www-pubs/trunk/2010-03-ASPLOS-Orthrus.html URL: http://llvm.org/viewvc/llvm-project/www-pubs/trunk/2010-03-ASPLOS-Orthrus.html?rev=98804&view=auto ============================================================================== --- www-pubs/trunk/2010-03-ASPLOS-Orthrus.html (added) +++ www-pubs/trunk/2010-03-ASPLOS-Orthrus.html Thu Mar 18 01:22:35 2010 @@ -0,0 +1,47 @@ + + + + + + Orthrus: Efficient Software Integrity Protection on Multi-core + + + +
        + Orthrus: Efficient Software Integrity Protection on Multi-core +
        +
        + Ruirui Huang, Daniel Y. Deng, G. Edward Suh +
        + +

        Abstract:

        +
        +

        This paper proposes an efficient hardware/software system that significantly enhances software security through diversified replication on multi-cores. Recent studies show that a large class of software attacks can be detected by running multiple versions of a program simultaneously and checking the consistency of their behaviors. However, execution of multiple replicas incurs significant overheads on today's computing platforms, especially with fine-grained comparisons necessary for high security. Orthrus exploits similarities in automatically generated replicas to enable simultaneous execution of those replicas with minimal overheads; the architecture reduces memory and bandwidth overheads by compressing multiple memory spaces together, and additional power consumption and silicon area by eliminating redundant computations. Utilizing the hardware architecture, Orthrus implements a fine-grained memory layout diversification with the LLVM compiler and can detect corruptio ns in both pointers and critical data. Experiments indicate that the Orthrus architecture incurs minimal overheads and provides a protection against a broad range of attacks.

        +
        + +

        Published:

        +
        + "Orthrus: Efficient Software Integrity Protection on Multi-core" +
        + Ruirui Huang, Daniel Y. Deng, G. Edward Suh +
        + +Proc. of the 15th international conference on Architectural Support for Programming Languages and Operating Systems, Pittsburgh, PA, March 2010. +
        +

        Download:

        +

        Paper:

        + + + +
        + Valid CSS! + Valid HTML 4.01! + + + Added: www-pubs/trunk/2010-03-ASPLOS-Orthrus.pdf URL: http://llvm.org/viewvc/llvm-project/www-pubs/trunk/2010-03-ASPLOS-Orthrus.pdf?rev=98804&view=auto ============================================================================== Binary files www-pubs/trunk/2010-03-ASPLOS-Orthrus.pdf (added) and www-pubs/trunk/2010-03-ASPLOS-Orthrus.pdf Thu Mar 18 01:22:35 2010 differ Added: www-pubs/trunk/2010-03-ASPLOS-Shoestring.html URL: http://llvm.org/viewvc/llvm-project/www-pubs/trunk/2010-03-ASPLOS-Shoestring.html?rev=98804&view=auto ============================================================================== --- www-pubs/trunk/2010-03-ASPLOS-Shoestring.html (added) +++ www-pubs/trunk/2010-03-ASPLOS-Shoestring.html Thu Mar 18 01:22:35 2010 @@ -0,0 +1,47 @@ + + + + + + Shoestring: Probabilistic Soft Error Reliability on the Cheap + + + +
        + Shoestring: Probabilistic Soft Error Reliability on the Cheap +
        +
        + Shuguang Feng, Shantanu Gupta, Amin Ansari, and Scott Mahlke +
        + +

        Abstract:

        +
        +

        Aggressive technology scaling provides designers with an ever increasing budget of cheaper and faster transistors. Unfortunately, this trend is accompanied by a decline in individual device reliability as transistors become increasingly susceptible to soft errors. We are quickly approaching a new era where resilience to soft errors is no longer a luxury that can be reserved for just processors in high-reliability, mission-critical domains. Even processors used in mainstream computing will soon require protection. However, due to tighter profit margins, reliable operation for these devices must come at little or no cost. This paper presents Shoestring, a minimally invasive software solution that provides high soft error coverage with very little overhead, enabling its deployment even in commodity processors with "shoestring" reliability budgets. Leveraging intelligent analysis at compile time, and exploiting low-cost, symptom-based error detection, Shoestring is able to fo cus its efforts on protecting statistically-vulnerable portions of program code. Shoestring effectively applies instruction duplication to protect only those segments of code that, when subjected to a soft error, are likely to result in user-visible faults without first exhibiting symptomatic behavior. Shoestring is able to recover from an additional 33.9% of soft errors that are undetected by a symptom-only approach, achieving an overall user-visible failure rate of 1.6%. This reliability improvement comes at a modest performance overhead of 15.8%.

        +
        + +

        Published:

        +
        + "Shoestring: Probabilistic Soft Error Reliability on the Cheap" +
        + Shuguang Feng, Shantanu Gupta, Amin Ansari, and Scott Mahlke +
        + +Proc. of the 15th international conference on Architectural Support for Programming Languages and Operating Systems, Pittsburgh, PA, March 2010. +
        +

        Download:

        +

        Paper:

        + + + +
        + Valid CSS! + Valid HTML 4.01! + + + Added: www-pubs/trunk/2010-03-ASPLOS-Shoestring.pdf URL: http://llvm.org/viewvc/llvm-project/www-pubs/trunk/2010-03-ASPLOS-Shoestring.pdf?rev=98804&view=auto ============================================================================== Binary files www-pubs/trunk/2010-03-ASPLOS-Shoestring.pdf (added) and www-pubs/trunk/2010-03-ASPLOS-Shoestring.pdf Thu Mar 18 01:22:35 2010 differ Modified: www-pubs/trunk/pubs.js URL: http://llvm.org/viewvc/llvm-project/www-pubs/trunk/pubs.js?rev=98804&r1=98803&r2=98804&view=diff ============================================================================== --- www-pubs/trunk/pubs.js (original) +++ www-pubs/trunk/pubs.js Thu Mar 18 01:22:35 2010 @@ -1,6 +1,27 @@ // The array should be sorted reverse-chronologically, and will be displayed on // the page in the order listed. var PUBS = [ + {url: "2010-03-ASPLOS-Shoestring.html", + title: "Shoestring: Probabilistic Soft Error Reliability on the Cheap", + published: "Proc. of the Fifteenth International Conference on Architectural Support for Programming Languages and Operating Systems (ASPLOS '10)", + author: "Shuguang Feng, Shantanu Gupta, Amin Ansari, and Scott Mahlke", + location: "Pittsburgh, PA", + month: 3, + year: 2010}, + {url: "2010-03-ASPLOS-Orthrus.html", + title: "Orthrus: Efficient Software Integrity Protection on Multi-core", + published: "Proc. of the Fifteenth International Conference on Architectural Support for Programming Languages and Operating Systems (ASPLOS '10)", + author: "Ruirui Huang, Daniel Y. Deng, G. Edward Suh", + location: "Pittsburgh, PA", + month: 3, + year: 2010}, + {url: "2010-03-ASPLOS-ConservationCores.html", + title: "Conservation Cores: Reducing the Energy of Mature Computations", + published: "Proc. of the Fifteenth International Conference on Architectural Support for Programming Languages and Operating Systems (ASPLOS '10)", + author: "Ganesh Venkatesh, Jack Sampson, Nathan Goulding, Saturnino Garcia, Vladyslav Bryksin, Jose Lugo-Martinez, Steven Swanson, Michael Bedford Taylor", + location: "Pittsburgh, PA", + month: 3, + year: 2010}, {url: "2010-03-ASPLOS-SpeculativeParallelization.html", title: "Speculative Parallelization using Software Multi-Threaded Transactions", published: "Proc. of the Fifteenth International Conference on Architectural Support for Programming Languages and Operating Systems (ASPLOS '10)", From resistor at mac.com Thu Mar 18 01:32:13 2010 From: resistor at mac.com (Owen Anderson) Date: Thu, 18 Mar 2010 06:32:13 -0000 Subject: [llvm-commits] [www-pubs] r98805 - in /www-pubs/trunk: 2010-03-GPGPU-ModelingGPGPU.html 2010-03-GPGPU-ModelingGPGPU.pdf pubs.js Message-ID: <20100318063213.222C62A6C12C@llvm.org> Author: resistor Date: Thu Mar 18 01:32:12 2010 New Revision: 98805 URL: http://llvm.org/viewvc/llvm-project?rev=98805&view=rev Log: Add a paper from GPGPU-3. Added: www-pubs/trunk/2010-03-GPGPU-ModelingGPGPU.html www-pubs/trunk/2010-03-GPGPU-ModelingGPGPU.pdf (with props) Modified: www-pubs/trunk/pubs.js Added: www-pubs/trunk/2010-03-GPGPU-ModelingGPGPU.html URL: http://llvm.org/viewvc/llvm-project/www-pubs/trunk/2010-03-GPGPU-ModelingGPGPU.html?rev=98805&view=auto ============================================================================== --- www-pubs/trunk/2010-03-GPGPU-ModelingGPGPU.html (added) +++ www-pubs/trunk/2010-03-GPGPU-ModelingGPGPU.html Thu Mar 18 01:32:12 2010 @@ -0,0 +1,49 @@ + + + + + + Modeling GPU-CPU Workloads and Systems + + + +
        + Modeling GPU-CPU Workloads and Systems +
        +
        + Andrew Kerr, Gregory Diamos, and Sudhakar Yalamanchili +
        + +

        Abstract:

        +
        +

        Heterogeneous systems, systems with multiple processors tailored for specialized tasks, are challenging programming environments. While it may be possible for domain experts to optimize a high performance application for a very specific and well documented system, it may not perform as well or even function on a different system. Developers who have less experience with either the application domain or the system architecture may devote a significant effort to writing a program that merely functions correctly. We believe that a comprehensive analysis and modeling frame-work is necessary to ease application development and automate program optimization on heterogeneous platforms.

        + +

        This paper reports on an empirical evaluation of 25 CUDA applications on four GPUs and three CPUs, leveraging the Ocelot dynamic compiler infrastructure which can execute and instrument the same CUDA applications on either target. Using a combination of instrumentation and statistical analysis, we record 37 different metrics for each application and use them to derive relationships between program behavior and performance on heterogeneous processors. These relationships are then fed into a modeling frame-work that attempts to predict the performance of similar classes of applications on different processors. Most significantly, this study identifies several non-intuitive relationships between program characteristics and demonstrates that it is possible to accurately model CUDA kernel performance using only metrics that are available before a kernel is executed.

        +
        + +

        Published:

        +
        + "Modeling GPU-CPU Workloads and Systems" +
        + Andrew Kerr, Gregory Diamos, and Sudhakar Yalamanchili +
        + +Proc. of the 3rd Workshop on General-Purpose Computation on Graphics Processing Units (GPGPU-3), Pittsburgh, PA, March 2010. +
        +

        Download:

        +

        Paper:

        + + + +
        + Valid CSS! + Valid HTML 4.01! + + + Added: www-pubs/trunk/2010-03-GPGPU-ModelingGPGPU.pdf URL: http://llvm.org/viewvc/llvm-project/www-pubs/trunk/2010-03-GPGPU-ModelingGPGPU.pdf?rev=98805&view=auto ============================================================================== Binary file - no diff available. Propchange: www-pubs/trunk/2010-03-GPGPU-ModelingGPGPU.pdf ------------------------------------------------------------------------------ svn:mime-type = application/octet-stream Modified: www-pubs/trunk/pubs.js URL: http://llvm.org/viewvc/llvm-project/www-pubs/trunk/pubs.js?rev=98805&r1=98804&r2=98805&view=diff ============================================================================== --- www-pubs/trunk/pubs.js (original) +++ www-pubs/trunk/pubs.js Thu Mar 18 01:32:12 2010 @@ -1,6 +1,13 @@ // The array should be sorted reverse-chronologically, and will be displayed on // the page in the order listed. var PUBS = [ + {url: "2010-03-GPGPU-ModelingGPGPU.html", + title: "Modeling GPU-CPU Workloads and Systems", + published: "Proc. of the 3rd Workshop on General-Purpose Computation on Graphics Processing Units (GPGPU-3)", + author: "Andrew Kerr, Gregory Diamos, and Sudhakar Yalamanchili", + location: "Pittsburgh, PA", + month: 3, + year: 2010}, {url: "2010-03-ASPLOS-Shoestring.html", title: "Shoestring: Probabilistic Soft Error Reliability on the Cheap", published: "Proc. of the Fifteenth International Conference on Architectural Support for Programming Languages and Operating Systems (ASPLOS '10)", From resistor at mac.com Thu Mar 18 01:43:15 2010 From: resistor at mac.com (Owen Anderson) Date: Thu, 18 Mar 2010 06:43:15 -0000 Subject: [llvm-commits] [www-pubs] r98807 - in /www-pubs/trunk: 2010-02-FPGA-BitLevel.html 2010-02-FPGA-BitLevel.pdf pubs.js Message-ID: <20100318064315.DE2B22A6C12C@llvm.org> Author: resistor Date: Thu Mar 18 01:43:15 2010 New Revision: 98807 URL: http://llvm.org/viewvc/llvm-project?rev=98807&view=rev Log: Add a paper from FPGA'10. Added: www-pubs/trunk/2010-02-FPGA-BitLevel.html www-pubs/trunk/2010-02-FPGA-BitLevel.pdf Modified: www-pubs/trunk/pubs.js Added: www-pubs/trunk/2010-02-FPGA-BitLevel.html URL: http://llvm.org/viewvc/llvm-project/www-pubs/trunk/2010-02-FPGA-BitLevel.html?rev=98807&view=auto ============================================================================== --- www-pubs/trunk/2010-02-FPGA-BitLevel.html (added) +++ www-pubs/trunk/2010-02-FPGA-BitLevel.html Thu Mar 18 01:43:15 2010 @@ -0,0 +1,48 @@ + + + + + + Bit-Level Optimization for High-Level Synthesis and FPGA-Based Acceleration + + + +
        + Bit-Level Optimization for High-Level Synthesis and FPGA-Based Acceleration +
        +
        + Jiyu Zhang, Zhiru Zhang, Sheng Zhou, Mingxing Tan, Xianhua Liu, Xu Cheng, Jason Cong +
        + +

        Abstract:

        +
        +

        Automated hardware design from behavior-level abstraction has drawn wide interest in FPGA-based acceleration and configurable computing research field. However, for many high-level programming languages, such as C/C++, the description of bitwise access and computation is not as direct as hardware description languages, and high-level synthesis of algorithmic descriptions may generate suboptimal implementations for bitwise computation-intensive applications. In this paper we introduce a bit-level transformation and optimization approach to assisting high-level synthesis of algorithmic descriptions. We introduce a bit-flow graph to capture bit-value information. Analysis and optimizing transformations can be performed on this representation, and the optimized results are transformed back to the standard data-flow graphs extended with a few instructions representing bitwise access. This allows high-level synthesis tools to automatically generate circuits with higher quality. Experiments show that our algorithm can reduce slice usage by 29.8% on average for a set of real-life benchmarks on Xilinx Virtex-4 FPGAs. In the meantime, the clock period is reduced by 13.6% on average, with an 11.4% latency reduction.

        +
        + +

        Published:

        +
        + "Bit-Level Optimization for High-Level Synthesis and FPGA-Based Acceleration" +
        + Jiyu Zhang, Zhiru Zhang, Sheng Zhou, Mingxing Tan, Xianhua Liu, Xu Cheng, Jason Cong +
        + +Proc. of the 18th Annual ACM/SIGDA International Symposium on Field Programmable Gate Arrays +, Monterey, CA, February 2010. +
        +

        Download:

        +

        Paper:

        + + + +
        + Valid CSS! + Valid HTML 4.01! + + + Added: www-pubs/trunk/2010-02-FPGA-BitLevel.pdf URL: http://llvm.org/viewvc/llvm-project/www-pubs/trunk/2010-02-FPGA-BitLevel.pdf?rev=98807&view=auto ============================================================================== Binary files www-pubs/trunk/2010-02-FPGA-BitLevel.pdf (added) and www-pubs/trunk/2010-02-FPGA-BitLevel.pdf Thu Mar 18 01:43:15 2010 differ Modified: www-pubs/trunk/pubs.js URL: http://llvm.org/viewvc/llvm-project/www-pubs/trunk/pubs.js?rev=98807&r1=98806&r2=98807&view=diff ============================================================================== --- www-pubs/trunk/pubs.js (original) +++ www-pubs/trunk/pubs.js Thu Mar 18 01:43:15 2010 @@ -43,14 +43,20 @@ location: "Pittsburgh, PA", month: 3, year: 2010}, - - {url: "2010-01-Wennborg-Thesis.html", - title: "Emulator Speed-up Using JIT and LLVM", - published: "Master's Thesis, Lund University", - location: "Lund, Sweden", - author: "Hans Wennborg", - month: 1, + {url: "2010-02-FPGA-BitLevel.html", + title: "Bit-Level Optimization for High-Level Synthesis and FPGA-Based Acceleration", + published: "Proc. of the 18th Annual ACM/SIGDA International Symposium on Field programmable Gate Arrays (FPGA'10)", + author: "Jiyu Zhang, Zhiru Zhang, Sheng Zhou, Mingxing Tan, Xianhua Liu, Xu Cheng, Jason Cong", + location: "Monterey, CA", + month: 2, year: 2010}, + {url: "2010-01-Wennborg-Thesis.html", + title: "Emulator Speed-up Using JIT and LLVM", + published: "Master's Thesis, Lund University", + location: "Lund, Sweden", + author: "Hans Wennborg", + month: 1, + year: 2010}, {url: "2009-10-LCPC-DataRestructuring.html", title: "Automatic Restructuring of Linked Data Structures", From resistor at mac.com Thu Mar 18 01:52:09 2010 From: resistor at mac.com (Owen Anderson) Date: Thu, 18 Mar 2010 06:52:09 -0000 Subject: [llvm-commits] [www-pubs] r98808 - in /www-pubs/trunk: 2010-05-ICSE-QualityOfService.html 2010-05-ICSE-QualityOfService.pdf pubs.js Message-ID: <20100318065209.5AF502A6C12C@llvm.org> Author: resistor Date: Thu Mar 18 01:52:09 2010 New Revision: 98808 URL: http://llvm.org/viewvc/llvm-project?rev=98808&view=rev Log: A paper in ICSE too. Added: www-pubs/trunk/2010-05-ICSE-QualityOfService.html www-pubs/trunk/2010-05-ICSE-QualityOfService.pdf Modified: www-pubs/trunk/pubs.js Added: www-pubs/trunk/2010-05-ICSE-QualityOfService.html URL: http://llvm.org/viewvc/llvm-project/www-pubs/trunk/2010-05-ICSE-QualityOfService.html?rev=98808&view=auto ============================================================================== --- www-pubs/trunk/2010-05-ICSE-QualityOfService.html (added) +++ www-pubs/trunk/2010-05-ICSE-QualityOfService.html Thu Mar 18 01:52:09 2010 @@ -0,0 +1,52 @@ + + + + + + Quality of Service Profiling + + + +
        + Quality of Service Profiling +
        +
        + Sasa Misailovic, Stelios Sidiroglou, Henry Hoffmann, Martin Rinard +
        + +

        Abstract:

        +
        +

        Many computations exhibit a trade off between execution time and quality of service. A video encoder, for example, can often encode frames more quickly if it is given the freedom to produce slightly lower quality video. A developer attempting to optimize such computations must navigate a complex trade-off space to find optimizations that appropriately balance quality of service and performance.

        + +

        We present a new quality of service profiler that is designed to help developers identify promising optimization opportunities in such computations. In contrast to standard profilers, which simply identify time-consuming parts of the computation, a quality of service profiler is designed to identify subcomputations that can be replaced with new (and potentially less accurate) subcomputations that deliver significantly increased performance in return for acceptably small quality of service losses.

        + +

        Our quality of service profiler uses loop perforation (which transforms loops to perform fewer iterations than the original loop) to obtain implementations that occupy different points in the performance/quality of service trade-off space. The rationale is that optimizable computations often contain loops that perform extra iterations, and that removing iterations, then observing the resulting effect on the quality of service, is an effective way to identify such optimizable subcomputations. Our experimental results from applying our implemented quality of service profiler to a challenging set of benchmark applications show that it can enable developers to identify promising optimization opportunities and deliver successful optimizations that substantially increase the performance with only small quality of service losses.

        +
        + +

        Published:

        +
        + "Quality of Service Profiling" +
        + Sasa Misailovic, Stelios Sidiroglou, Henry Hoffmann, Martin Rinard +
        + +Proc. of the 2010 IEEE 32st International Conference on Software Engineering +, Cape Town, South Africa, May 2010. +
        +

        Download:

        +

        Paper:

        + + + +
        + Valid CSS! + Valid HTML 4.01! + + + Added: www-pubs/trunk/2010-05-ICSE-QualityOfService.pdf URL: http://llvm.org/viewvc/llvm-project/www-pubs/trunk/2010-05-ICSE-QualityOfService.pdf?rev=98808&view=auto ============================================================================== Binary files www-pubs/trunk/2010-05-ICSE-QualityOfService.pdf (added) and www-pubs/trunk/2010-05-ICSE-QualityOfService.pdf Thu Mar 18 01:52:09 2010 differ Modified: www-pubs/trunk/pubs.js URL: http://llvm.org/viewvc/llvm-project/www-pubs/trunk/pubs.js?rev=98808&r1=98807&r2=98808&view=diff ============================================================================== --- www-pubs/trunk/pubs.js (original) +++ www-pubs/trunk/pubs.js Thu Mar 18 01:52:09 2010 @@ -1,6 +1,13 @@ // The array should be sorted reverse-chronologically, and will be displayed on // the page in the order listed. var PUBS = [ + {url: "2010-05-ICSE-QualityOfService.html", + title: "Quality of Service Profiling", + published: "Proc. of the 2010 IEEE 32st International Conference on Software Engineering (ICSE'10)", + author: "Sasa Misailovic, Stelios Sidiroglou, Henry Hoffmann, Martin Rinard", + location: "Cape Town, South Africa", + month: 5, + year: 2010}, {url: "2010-03-GPGPU-ModelingGPGPU.html", title: "Modeling GPU-CPU Workloads and Systems", published: "Proc. of the 3rd Workshop on General-Purpose Computation on Graphics Processing Units (GPGPU-3)", @@ -45,7 +52,7 @@ year: 2010}, {url: "2010-02-FPGA-BitLevel.html", title: "Bit-Level Optimization for High-Level Synthesis and FPGA-Based Acceleration", - published: "Proc. of the 18th Annual ACM/SIGDA International Symposium on Field programmable Gate Arrays (FPGA'10)", + published: "Proc. of the 18th Annual ACM/SIGDA International Symposium on Field Programmable Gate Arrays (FPGA'10)", author: "Jiyu Zhang, Zhiru Zhang, Sheng Zhou, Mingxing Tan, Xianhua Liu, Xu Cheng, Jason Cong", location: "Monterey, CA", month: 2, From sabre at nondot.org Thu Mar 18 01:52:15 2010 From: sabre at nondot.org (Chris Lattner) Date: Thu, 18 Mar 2010 06:52:15 -0000 Subject: [llvm-commits] [llvm] r98809 - /llvm/trunk/docs/ReleaseNotes.html Message-ID: <20100318065215.CCFFD2A6C12D@llvm.org> Author: lattner Date: Thu Mar 18 01:52:15 2010 New Revision: 98809 URL: http://llvm.org/viewvc/llvm-project?rev=98809&view=rev Log: add a couple blurbs back Modified: llvm/trunk/docs/ReleaseNotes.html Modified: llvm/trunk/docs/ReleaseNotes.html URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/docs/ReleaseNotes.html?rev=98809&r1=98808&r2=98809&view=diff ============================================================================== --- llvm/trunk/docs/ReleaseNotes.html (original) +++ llvm/trunk/docs/ReleaseNotes.html Thu Mar 18 01:52:15 2010 @@ -366,12 +366,10 @@

        -Need update. - +compiler.

        From evan.cheng at apple.com Thu Mar 18 01:55:42 2010 From: evan.cheng at apple.com (Evan Cheng) Date: Thu, 18 Mar 2010 06:55:42 -0000 Subject: [llvm-commits] [llvm] r98810 - in /llvm/trunk: lib/Target/X86/X86Subtarget.cpp lib/Target/X86/X86Subtarget.h test/CodeGen/X86/2007-01-08-InstrSched.ll test/CodeGen/X86/lsr-reuse.ll test/CodeGen/X86/sse2.ll test/CodeGen/X86/sse3.ll Message-ID: <20100318065542.890022A6C12C@llvm.org> Author: evancheng Date: Thu Mar 18 01:55:42 2010 New Revision: 98810 URL: http://llvm.org/viewvc/llvm-project?rev=98810&view=rev Log: Turning off post-ra scheduling for x86. It isn't a consistent win. Modified: llvm/trunk/lib/Target/X86/X86Subtarget.cpp llvm/trunk/lib/Target/X86/X86Subtarget.h llvm/trunk/test/CodeGen/X86/2007-01-08-InstrSched.ll llvm/trunk/test/CodeGen/X86/lsr-reuse.ll llvm/trunk/test/CodeGen/X86/sse2.ll llvm/trunk/test/CodeGen/X86/sse3.ll Modified: llvm/trunk/lib/Target/X86/X86Subtarget.cpp URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Target/X86/X86Subtarget.cpp?rev=98810&r1=98809&r2=98810&view=diff ============================================================================== --- llvm/trunk/lib/Target/X86/X86Subtarget.cpp (original) +++ llvm/trunk/lib/Target/X86/X86Subtarget.cpp Thu Mar 18 01:55:42 2010 @@ -366,12 +366,3 @@ if (StackAlignment) stackAlignment = StackAlignment; } - -bool X86Subtarget::enablePostRAScheduler( - CodeGenOpt::Level OptLevel, - TargetSubtarget::AntiDepBreakMode& Mode, - RegClassVector& CriticalPathRCs) const { - Mode = TargetSubtarget::ANTIDEP_CRITICAL; - CriticalPathRCs.clear(); - return OptLevel >= CodeGenOpt::Aggressive; -} Modified: llvm/trunk/lib/Target/X86/X86Subtarget.h URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Target/X86/X86Subtarget.h?rev=98810&r1=98809&r2=98810&view=diff ============================================================================== --- llvm/trunk/lib/Target/X86/X86Subtarget.h (original) +++ llvm/trunk/lib/Target/X86/X86Subtarget.h Thu Mar 18 01:55:42 2010 @@ -230,12 +230,6 @@ /// indicating the number of scheduling cycles of backscheduling that /// should be attempted. unsigned getSpecialAddressLatency() const; - - /// enablePostRAScheduler - X86 target is enabling post-alloc scheduling - /// at 'More' optimization level. - bool enablePostRAScheduler(CodeGenOpt::Level OptLevel, - TargetSubtarget::AntiDepBreakMode& Mode, - RegClassVector& CriticalPathRCs) const; }; } // End llvm namespace Modified: llvm/trunk/test/CodeGen/X86/2007-01-08-InstrSched.ll URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/CodeGen/X86/2007-01-08-InstrSched.ll?rev=98810&r1=98809&r2=98810&view=diff ============================================================================== --- llvm/trunk/test/CodeGen/X86/2007-01-08-InstrSched.ll (original) +++ llvm/trunk/test/CodeGen/X86/2007-01-08-InstrSched.ll Thu Mar 18 01:55:42 2010 @@ -11,12 +11,12 @@ %tmp14 = fadd float %tmp12, %tmp7 ret float %tmp14 -; CHECK: mulss LCPI1_3(%rip) -; CHECK-NEXT: mulss LCPI1_0(%rip) -; CHECK-NEXT: mulss LCPI1_1(%rip) -; CHECK-NEXT: mulss LCPI1_2(%rip) -; CHECK-NEXT: addss -; CHECK-NEXT: addss -; CHECK-NEXT: addss -; CHECK-NEXT: ret +; CHECK: mulss LCPI1_0(%rip) +; CHECK: mulss LCPI1_1(%rip) +; CHECK: addss +; CHECK: mulss LCPI1_2(%rip) +; CHECK: addss +; CHECK: mulss LCPI1_3(%rip) +; CHECK: addss +; CHECK: ret } Modified: llvm/trunk/test/CodeGen/X86/lsr-reuse.ll URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/CodeGen/X86/lsr-reuse.ll?rev=98810&r1=98809&r2=98810&view=diff ============================================================================== --- llvm/trunk/test/CodeGen/X86/lsr-reuse.ll (original) +++ llvm/trunk/test/CodeGen/X86/lsr-reuse.ll Thu Mar 18 01:55:42 2010 @@ -8,10 +8,10 @@ ; CHECK: full_me_0: ; CHECK: movsd (%rsi), %xmm0 -; CHECK: addq $8, %rsi ; CHECK: mulsd (%rdx), %xmm0 -; CHECK: addq $8, %rdx ; CHECK: movsd %xmm0, (%rdi) +; CHECK: addq $8, %rsi +; CHECK: addq $8, %rdx ; CHECK: addq $8, %rdi ; CHECK: decq %rcx ; CHECK: jne @@ -53,10 +53,10 @@ ; CHECK: mulsd -2048(%rdx), %xmm0 ; CHECK: movsd %xmm0, -2048(%rdi) ; CHECK: movsd (%rsi), %xmm0 -; CHECK: addq $8, %rsi ; CHECK: divsd (%rdx), %xmm0 -; CHECK: addq $8, %rdx ; CHECK: movsd %xmm0, (%rdi) +; CHECK: addq $8, %rsi +; CHECK: addq $8, %rdx ; CHECK: addq $8, %rdi ; CHECK: decq %rcx ; CHECK: jne @@ -99,10 +99,10 @@ ; CHECK: mulsd (%rdx), %xmm0 ; CHECK: movsd %xmm0, (%rdi) ; CHECK: movsd -2048(%rsi), %xmm0 -; CHECK: addq $8, %rsi ; CHECK: divsd -2048(%rdx), %xmm0 -; CHECK: addq $8, %rdx ; CHECK: movsd %xmm0, -2048(%rdi) +; CHECK: addq $8, %rsi +; CHECK: addq $8, %rdx ; CHECK: addq $8, %rdi ; CHECK: decq %rcx ; CHECK: jne @@ -144,10 +144,10 @@ ; CHECK: mulsd (%rdx), %xmm0 ; CHECK: movsd %xmm0, (%rdi) ; CHECK: movsd -4096(%rsi), %xmm0 -; CHECK: addq $8, %rsi ; CHECK: divsd -4096(%rdx), %xmm0 -; CHECK: addq $8, %rdx ; CHECK: movsd %xmm0, -4096(%rdi) +; CHECK: addq $8, %rsi +; CHECK: addq $8, %rdx ; CHECK: addq $8, %rdi ; CHECK: decq %rcx ; CHECK: jne @@ -310,10 +310,10 @@ ; CHECK: addsd (%rsi), %xmm0 ; CHECK: movsd %xmm0, (%rdx) ; CHECK: movsd 40(%rdi), %xmm0 -; CHECK: addq $8, %rdi ; CHECK: subsd 40(%rsi), %xmm0 -; CHECK: addq $8, %rsi ; CHECK: movsd %xmm0, 40(%rdx) +; CHECK: addq $8, %rdi +; CHECK: addq $8, %rsi ; CHECK: addq $8, %rdx ; CHECK: decq %rcx ; CHECK: jne Modified: llvm/trunk/test/CodeGen/X86/sse2.ll URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/CodeGen/X86/sse2.ll?rev=98810&r1=98809&r2=98810&view=diff ============================================================================== --- llvm/trunk/test/CodeGen/X86/sse2.ll (original) +++ llvm/trunk/test/CodeGen/X86/sse2.ll Thu Mar 18 01:55:42 2010 @@ -10,10 +10,10 @@ ; CHECK: t1: ; CHECK: movl 8(%esp), %eax -; CHECK-NEXT: movl 4(%esp), %ecx ; CHECK-NEXT: movapd (%eax), %xmm0 ; CHECK-NEXT: movlpd 12(%esp), %xmm0 -; CHECK-NEXT: movapd %xmm0, (%ecx) +; CHECK-NEXT: movl 4(%esp), %eax +; CHECK-NEXT: movapd %xmm0, (%eax) ; CHECK-NEXT: ret } @@ -26,9 +26,9 @@ ; CHECK: t2: ; CHECK: movl 8(%esp), %eax -; CHECK-NEXT: movl 4(%esp), %ecx ; CHECK-NEXT: movapd (%eax), %xmm0 ; CHECK-NEXT: movhpd 12(%esp), %xmm0 -; CHECK-NEXT: movapd %xmm0, (%ecx) +; CHECK-NEXT: movl 4(%esp), %eax +; CHECK-NEXT: movapd %xmm0, (%eax) ; CHECK-NEXT: ret } Modified: llvm/trunk/test/CodeGen/X86/sse3.ll URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/CodeGen/X86/sse3.ll?rev=98810&r1=98809&r2=98810&view=diff ============================================================================== --- llvm/trunk/test/CodeGen/X86/sse3.ll (original) +++ llvm/trunk/test/CodeGen/X86/sse3.ll Thu Mar 18 01:55:42 2010 @@ -17,8 +17,8 @@ ; X64: t0: ; X64: movddup (%rsi), %xmm0 -; X64: xorl %eax, %eax ; X64: pshuflw $0, %xmm0, %xmm0 +; X64: xorl %eax, %eax ; X64: pinsrw $0, %eax, %xmm0 ; X64: movaps %xmm0, (%rdi) ; X64: ret @@ -169,11 +169,11 @@ ret void ; X64: t10: ; X64: pextrw $4, %xmm0, %eax -; X64: pextrw $6, %xmm0, %edx ; X64: movlhps %xmm1, %xmm1 ; X64: pshuflw $8, %xmm1, %xmm1 ; X64: pinsrw $2, %eax, %xmm1 -; X64: pinsrw $3, %edx, %xmm1 +; X64: pextrw $6, %xmm0, %eax +; X64: pinsrw $3, %eax, %xmm1 } @@ -184,8 +184,8 @@ ret <8 x i16> %tmp7 ; X64: t11: -; X64: movlhps %xmm0, %xmm0 ; X64: movd %xmm1, %eax +; X64: movlhps %xmm0, %xmm0 ; X64: pshuflw $1, %xmm0, %xmm0 ; X64: pinsrw $1, %eax, %xmm0 ; X64: ret @@ -198,8 +198,8 @@ ret <8 x i16> %tmp9 ; X64: t12: -; X64: movlhps %xmm0, %xmm0 ; X64: pextrw $3, %xmm1, %eax +; X64: movlhps %xmm0, %xmm0 ; X64: pshufhw $3, %xmm0, %xmm0 ; X64: pinsrw $5, %eax, %xmm0 ; X64: ret From resistor at mac.com Thu Mar 18 01:59:32 2010 From: resistor at mac.com (Owen Anderson) Date: Thu, 18 Mar 2010 06:59:32 -0000 Subject: [llvm-commits] [www-pubs] r98811 - in /www-pubs/trunk: 2010-04-EUROSYS-RevNIC.html 2010-04-EUROSYS-RevNIC.pdf pubs.js Message-ID: <20100318065932.D9C462A6C12C@llvm.org> Author: resistor Date: Thu Mar 18 01:59:32 2010 New Revision: 98811 URL: http://llvm.org/viewvc/llvm-project?rev=98811&view=rev Log: Add a paper from EuroSys. Added: www-pubs/trunk/2010-04-EUROSYS-RevNIC.html www-pubs/trunk/2010-04-EUROSYS-RevNIC.pdf (with props) Modified: www-pubs/trunk/pubs.js Added: www-pubs/trunk/2010-04-EUROSYS-RevNIC.html URL: http://llvm.org/viewvc/llvm-project/www-pubs/trunk/2010-04-EUROSYS-RevNIC.html?rev=98811&view=auto ============================================================================== --- www-pubs/trunk/2010-04-EUROSYS-RevNIC.html (added) +++ www-pubs/trunk/2010-04-EUROSYS-RevNIC.html Thu Mar 18 01:59:32 2010 @@ -0,0 +1,52 @@ + + + + + + Reverse Engineering of Binary Device Drivers with RevNIC + + + +
        + Reverse Engineering of Binary Device Drivers with RevNIC +
        +
        + Vitaly Chipounov and George Candea +
        + +

        Abstract:

        +
        +

        This paper presents a technique that helps automate the reverse engineering of device drivers. It takes a closed-source binary driver, automatically reverse engineers the driver???s logic, and synthesizes new device driver code that implements the exact same hardware protocol as the original driver. This code can be targeted at the same or a different OS. No vendor documentation or source code is required.

        + +

        Drivers are often proprietary and available for only one or two operating systems, thus restricting the range of device support on all other OSes. Restricted device support leads to low market viability of new OSes and hampers OS researchers in their efforts to make their ideas available to the ???real world.??? Reverse engineering can help automate the porting of drivers, as well as produce replacement drivers with fewer bugs and fewer security vulnerabilities.

        + +

        Our technique is embodied in RevNIC, a tool for reverse engineering network drivers. We use RevNIC to reverse engineer four proprietary Windows drivers and port them to four different OSes, both for PCs and embedded systems. The synthesized network drivers deliver performance nearly identical to that of the original drivers.

        +
        + +

        Published:

        +
        + "Reverse Engineering of Binary Device Drivers with RevNIC" +
        + Vitaly Chipounov and George Candea +
        + +Proc. of the 5th ACM European Conference on Computer Systems +, Paris, France, April 2010. +
        +

        Download:

        +

        Paper:

        + + + +
        + Valid CSS! + Valid HTML 4.01! + + + Added: www-pubs/trunk/2010-04-EUROSYS-RevNIC.pdf URL: http://llvm.org/viewvc/llvm-project/www-pubs/trunk/2010-04-EUROSYS-RevNIC.pdf?rev=98811&view=auto ============================================================================== Binary file - no diff available. Propchange: www-pubs/trunk/2010-04-EUROSYS-RevNIC.pdf ------------------------------------------------------------------------------ svn:mime-type = application/octet-stream Modified: www-pubs/trunk/pubs.js URL: http://llvm.org/viewvc/llvm-project/www-pubs/trunk/pubs.js?rev=98811&r1=98810&r2=98811&view=diff ============================================================================== --- www-pubs/trunk/pubs.js (original) +++ www-pubs/trunk/pubs.js Thu Mar 18 01:59:32 2010 @@ -8,6 +8,13 @@ location: "Cape Town, South Africa", month: 5, year: 2010}, + {url: "2010-04-EUROSYS-RevNIC.html", + title: "Reverse Engineering of Binary Device Drivers with RevNIC", + published: "Proc. of the 5th ACM European Conference on Computer Systems (EuroSys'10)", + author: "Vitaly Chipounov and George Candea", + location: "Paris, France", + month: 4, + year: 2010}, {url: "2010-03-GPGPU-ModelingGPGPU.html", title: "Modeling GPU-CPU Workloads and Systems", published: "Proc. of the 3rd Workshop on General-Purpose Computation on Graphics Processing Units (GPGPU-3)", From jyasskin at google.com Thu Mar 18 02:00:13 2010 From: jyasskin at google.com (Jeffrey Yasskin) Date: Thu, 18 Mar 2010 07:00:13 -0000 Subject: [llvm-commits] [llvm] r98813 - in /llvm/trunk/utils/lit/lit: TestFormats.py TestRunner.py Message-ID: <20100318070013.2927C2A6C12C@llvm.org> Author: jyasskin Date: Thu Mar 18 02:00:12 2010 New Revision: 98813 URL: http://llvm.org/viewvc/llvm-project?rev=98813&view=rev Log: Avoid a problem in libc_freeres() seen on a linux-i686 buildbot when running under valgrind: ==19577== Invalid free() / delete / delete[] ==19577== at 0x4C9C866: free (vg_replace_malloc.c:325) ==19577== by 0x5121104: ??? (in /lib/libc-2.10.2.so) ==19577== by 0x4C97412: _vgnU_freeres (vg_preloaded.c:62) ==19577== by 0x5041486: __run_exit_handlers (exit.c:93) ==19577== by 0x50414FE: exit (exit.c:100) ==19577== by 0x5028B5C: (below main) (libc-start.c:254) ==19577== Address 0xffffffff is not stack'd, malloc'd or (recently) free'd ==19577== Apparently this happens under certain versions of glibc, so valgrind provides the --run-libc-freeres=no option to avoid calling freeres(). This may increase the number of "still reachable" blocks valgrind reports, but we don't care about those, while this error breaks the buildbots. There are upstream bugs about this at http://sourceware.org/bugzilla/show_bug.cgi?id=10610 and http://bugs.kde.org/show_bug.cgi?id=167483, but they don't look likely to be fixed. Modified: llvm/trunk/utils/lit/lit/TestFormats.py llvm/trunk/utils/lit/lit/TestRunner.py Modified: llvm/trunk/utils/lit/lit/TestFormats.py URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/utils/lit/lit/TestFormats.py?rev=98813&r1=98812&r2=98813&view=diff ============================================================================== --- llvm/trunk/utils/lit/lit/TestFormats.py (original) +++ llvm/trunk/utils/lit/lit/TestFormats.py Thu Mar 18 02:00:12 2010 @@ -73,7 +73,7 @@ cmd = [testPath, '--gtest_filter=' + testName] if litConfig.useValgrind: - valgrindArgs = ['valgrind', '-q', + valgrindArgs = ['valgrind', '-q', '--run-libc-freeres=no', '--tool=memcheck', '--trace-children=yes', '--error-exitcode=123'] valgrindArgs.extend(litConfig.valgrindArgs) Modified: llvm/trunk/utils/lit/lit/TestRunner.py URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/utils/lit/lit/TestRunner.py?rev=98813&r1=98812&r2=98813&view=diff ============================================================================== --- llvm/trunk/utils/lit/lit/TestRunner.py (original) +++ llvm/trunk/utils/lit/lit/TestRunner.py Thu Mar 18 02:00:12 2010 @@ -253,7 +253,7 @@ return (Test.FAIL, "Tcl 'exec' parse error on: %r" % ln) if litConfig.useValgrind: - valgrindArgs = ['valgrind', '-q', + valgrindArgs = ['valgrind', '-q', '--run-libc-freeres=no', '--tool=memcheck', '--trace-children=yes', '--error-exitcode=123'] valgrindArgs.extend(litConfig.valgrindArgs) @@ -339,7 +339,7 @@ if litConfig.useValgrind: # FIXME: Running valgrind on sh is overkill. We probably could just # run on clang with no real loss. - valgrindArgs = ['valgrind', '-q', + valgrindArgs = ['valgrind', '-q', '--run-libc-freeres=no', '--tool=memcheck', '--trace-children=yes', '--error-exitcode=123'] valgrindArgs.extend(litConfig.valgrindArgs) From resistor at mac.com Thu Mar 18 02:05:45 2010 From: resistor at mac.com (Owen Anderson) Date: Thu, 18 Mar 2010 07:05:45 -0000 Subject: [llvm-commits] [www-pubs] r98814 - in /www-pubs/trunk: 2010-04-EUROSYS-ExecutionSynthesis.html 2010-04-EUROSYS-ExecutionSynthesis.pdf pubs.js Message-ID: <20100318070545.8EDEE2A6C12C@llvm.org> Author: resistor Date: Thu Mar 18 02:05:45 2010 New Revision: 98814 URL: http://llvm.org/viewvc/llvm-project?rev=98814&view=rev Log: Another one from EuroSys. Added: www-pubs/trunk/2010-04-EUROSYS-ExecutionSynthesis.html www-pubs/trunk/2010-04-EUROSYS-ExecutionSynthesis.pdf (with props) Modified: www-pubs/trunk/pubs.js Added: www-pubs/trunk/2010-04-EUROSYS-ExecutionSynthesis.html URL: http://llvm.org/viewvc/llvm-project/www-pubs/trunk/2010-04-EUROSYS-ExecutionSynthesis.html?rev=98814&view=auto ============================================================================== --- www-pubs/trunk/2010-04-EUROSYS-ExecutionSynthesis.html (added) +++ www-pubs/trunk/2010-04-EUROSYS-ExecutionSynthesis.html Thu Mar 18 02:05:45 2010 @@ -0,0 +1,52 @@ + + + + + + Execution Synthesis: A Technique for Automated Software Debugging + + + +
        + Execution Synthesis: A Technique for Automated Software Debugging +
        +
        + Cristian Zamfir and George Candea +
        + +

        Abstract:

        +
        +

        Debugging real systems is hard, requires deep knowledge of the code, and is time-consuming. Bug reports rarely provide sufficient information, thus forcing developers to turn into detectives searching for an explanation of how the program could have arrived at the reported failure point.

        + +

        Execution synthesis is a technique for automating this detective work: given a program and a bug report, it automatically produces an execution of the program that leads to the reported bug symptoms. Using a combination of static analysis and symbolic execution, it ???synthesizes??? a thread schedule and various required program inputs that cause the bug to manifest. The synthesized execution can be played back deterministically in a regular debugger, like gdb. This is particularly useful in debugging concurrency bugs.

        + +

        Our technique requires no runtime tracing or program modifications, thus incurring no runtime overhead and being practical for use in production systems. We evaluate ESD, a debugger based on execution synthesis on popular software (e.g., the SQLite database, ghttpd Web server, HawkNL network library, UNIX utilities): starting from mere bug reports, ESD reproduces on its own several real concurrency and memory safety bugs in less than three minutes.

        +
        + +

        Published:

        +
        + "Execution Synthesis: A Technique for Automated Software Debugging" +
        + Cristian Zamfir and George Candea +
        + +Proc. of the 5th ACM European Conference on Computer Systems +, Paris, France, April 2010. +
        +

        Download:

        +

        Paper:

        + + + +
        + Valid CSS! + Valid HTML 4.01! + + + Added: www-pubs/trunk/2010-04-EUROSYS-ExecutionSynthesis.pdf URL: http://llvm.org/viewvc/llvm-project/www-pubs/trunk/2010-04-EUROSYS-ExecutionSynthesis.pdf?rev=98814&view=auto ============================================================================== Binary file - no diff available. Propchange: www-pubs/trunk/2010-04-EUROSYS-ExecutionSynthesis.pdf ------------------------------------------------------------------------------ svn:mime-type = application/octet-stream Modified: www-pubs/trunk/pubs.js URL: http://llvm.org/viewvc/llvm-project/www-pubs/trunk/pubs.js?rev=98814&r1=98813&r2=98814&view=diff ============================================================================== --- www-pubs/trunk/pubs.js (original) +++ www-pubs/trunk/pubs.js Thu Mar 18 02:05:45 2010 @@ -15,6 +15,13 @@ location: "Paris, France", month: 4, year: 2010}, + {url: "2010-04-EUROSYS-ExecutionSynthesis.html", + title: "Execution Synthesis: A Technique for Automated Software Debugging", + published: "Proc. of the 5th ACM European Conference on Computer Systems (EuroSys'10)", + author: "Cristian Zamfir and George Candea", + location: "Paris, France", + month: 4, + year: 2010}, {url: "2010-03-GPGPU-ModelingGPGPU.html", title: "Modeling GPU-CPU Workloads and Systems", published: "Proc. of the 3rd Workshop on General-Purpose Computation on Graphics Processing Units (GPGPU-3)", From resistor at mac.com Thu Mar 18 02:13:09 2010 From: resistor at mac.com (Owen Anderson) Date: Thu, 18 Mar 2010 07:13:09 -0000 Subject: [llvm-commits] [www-pubs] r98815 - in /www-pubs/trunk: 2010-02-IPSJ-CustomInstruction.html 2010-02-IPSJ-CustomInstruction.pdf pubs.js Message-ID: <20100318071309.236342A6C12C@llvm.org> Author: resistor Date: Thu Mar 18 02:13:08 2010 New Revision: 98815 URL: http://llvm.org/viewvc/llvm-project?rev=98815&view=rev Log: Last paper for tonight. Added: www-pubs/trunk/2010-02-IPSJ-CustomInstruction.html www-pubs/trunk/2010-02-IPSJ-CustomInstruction.pdf (with props) Modified: www-pubs/trunk/pubs.js Added: www-pubs/trunk/2010-02-IPSJ-CustomInstruction.html URL: http://llvm.org/viewvc/llvm-project/www-pubs/trunk/2010-02-IPSJ-CustomInstruction.html?rev=98815&view=auto ============================================================================== --- www-pubs/trunk/2010-02-IPSJ-CustomInstruction.html (added) +++ www-pubs/trunk/2010-02-IPSJ-CustomInstruction.html Thu Mar 18 02:13:08 2010 @@ -0,0 +1,48 @@ + + + + + + Custom Instruction Generation for Configurable Processors with Limited Numbers of Operands + + + +
        + Custom Instruction Generation for Configurable Processors with Limited Numbers of Operands +
        +
        + Kenshu Seto and Masahiro Fujita +
        + +

        Abstract:

        +
        +

        This paper presents a novel framework to generating efficient custom instructions for common configurable processors with limited numbers of I/O ports in the register files and fixed-length instruction formats, such as RISCs. Unlike previous approaches which generate a single custom instruction from each subgraph, our approach generates a sequence of multiple custom instructions from each subgraph by applying high-level synthesis techniques such as scheduling and binding to the subgraphs. Because of this feature, our approach can provide both of the following two advantages simultaneously: (1) generation of effective custom instructions from Multiple Inputs Multiple Outputs (MIMO) subgraphs without any change in the configurable processor hardware and the instruction format, and (2) resource sharing among custom instructions. We performed synthesis, placement and routing of the automatically generated Custom Functional Units (CFUs) on an FPGA. Experimental results showed that our approach could generate custom instructions with significant speedups of 28% on average compared to a state-of-the-art framework of custom instruction generation for configurable processors with limited numbers of I/O ports in the register file and fixed-length instruction formats.

        +
        + +

        Published:

        +
        + "Custom Instruction Generation for Configurable Processors with Limited Numbers of Operands" +
        + Kenshu Seto and Masahiro Fujita +
        + +IPSJ Transactions on System LSI Design Methodology +, Volume 3. +
        +

        Download:

        +

        Paper:

        + + + +
        + Valid CSS! + Valid HTML 4.01! + + + Added: www-pubs/trunk/2010-02-IPSJ-CustomInstruction.pdf URL: http://llvm.org/viewvc/llvm-project/www-pubs/trunk/2010-02-IPSJ-CustomInstruction.pdf?rev=98815&view=auto ============================================================================== Binary file - no diff available. Propchange: www-pubs/trunk/2010-02-IPSJ-CustomInstruction.pdf ------------------------------------------------------------------------------ svn:mime-type = application/octet-stream Modified: www-pubs/trunk/pubs.js URL: http://llvm.org/viewvc/llvm-project/www-pubs/trunk/pubs.js?rev=98815&r1=98814&r2=98815&view=diff ============================================================================== --- www-pubs/trunk/pubs.js (original) +++ www-pubs/trunk/pubs.js Thu Mar 18 02:13:08 2010 @@ -71,6 +71,12 @@ location: "Monterey, CA", month: 2, year: 2010}, + {url: "2010-02-IPSJ-CustomInstruction.html", + title: "Custom Instruction Generation for Configurable Processors with Limited Numbers of Operands", + published: "IPSJ Transactions on System LSI Design Methodology", + author: "Kenshu Seto and Masahiro Fujita", + month: 2, + year: 2010}, {url: "2010-01-Wennborg-Thesis.html", title: "Emulator Speed-up Using JIT and LLVM", published: "Master's Thesis, Lund University", From baldrick at free.fr Thu Mar 18 03:56:31 2010 From: baldrick at free.fr (Duncan Sands) Date: Thu, 18 Mar 2010 09:56:31 +0100 Subject: [llvm-commits] [llvm] r98778 - /llvm/trunk/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp In-Reply-To: <20100317235237.9F8712A6C12C@llvm.org> References: <20100317235237.9F8712A6C12C@llvm.org> Message-ID: <4BA1EABF.5020800@free.fr> Hi Devang, > --- llvm/trunk/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp (original) > +++ llvm/trunk/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp Wed Mar 17 18:52:37 2010 > @@ -4282,6 +4282,9 @@ > --BBI) { > if (&*BBI == I) > break; > + // Debug info intrinsic does not intefer during tail call optimization. intefer -> interfere That said, how about: "Debug info intrinsics do not get in the way of tail call optimization." Ciao, Duncan. From benny.kra at googlemail.com Thu Mar 18 07:18:36 2010 From: benny.kra at googlemail.com (Benjamin Kramer) Date: Thu, 18 Mar 2010 12:18:36 -0000 Subject: [llvm-commits] [llvm] r98819 - /llvm/trunk/lib/Target/X86/Disassembler/X86DisassemblerDecoder.c Message-ID: <20100318121836.5A1ED2A6C12C@llvm.org> Author: d0k Date: Thu Mar 18 07:18:36 2010 New Revision: 98819 URL: http://llvm.org/viewvc/llvm-project?rev=98819&view=rev Log: Try to fix a valgrind error on 32 bit platforms: use %zu instead of %llu to format a size_t. Modified: llvm/trunk/lib/Target/X86/Disassembler/X86DisassemblerDecoder.c Modified: llvm/trunk/lib/Target/X86/Disassembler/X86DisassemblerDecoder.c URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Target/X86/Disassembler/X86DisassemblerDecoder.c?rev=98819&r1=98818&r2=98819&view=diff ============================================================================== --- llvm/trunk/lib/Target/X86/Disassembler/X86DisassemblerDecoder.c (original) +++ llvm/trunk/lib/Target/X86/Disassembler/X86DisassemblerDecoder.c Thu Mar 18 07:18:36 2010 @@ -1355,8 +1355,8 @@ insn->length = insn->readerCursor - insn->startLocation; - dbgprintf(insn, "Read from 0x%llx to 0x%llx: length %llu", - startLoc, insn->readerCursor, insn->length); + dbgprintf(insn, "Read from 0x%llx to 0x%llx: length %zu", + startLoc, insn->readerCursor, insn->length); if (insn->length > 15) dbgprintf(insn, "Instruction exceeds 15-byte limit"); From kovarththanan.rajaratnam at gmail.com Thu Mar 18 08:16:39 2010 From: kovarththanan.rajaratnam at gmail.com (Kovarththanan Rajaratnam) Date: Thu, 18 Mar 2010 13:16:39 -0000 Subject: [llvm-commits] [llvm] r98820 - /llvm/trunk/utils/TableGen/ClangDiagnosticsEmitter.cpp Message-ID: <20100318131639.232E42A6C12C@llvm.org> Author: krj Date: Thu Mar 18 08:16:38 2010 New Revision: 98820 URL: http://llvm.org/viewvc/llvm-project?rev=98820&view=rev Log: Add an extra newline to separate PP directives from the contents Modified: