Dear all, I have written an assembler which reads assembly instructions and produces the equivalent binary. I have a problem. Although I set the bit range and immediate type for an instruction like add which accepts a register and an immediate value, I can simply overflow that value and llvm/tablegen doesn't care! for example for a i8imm imm value (bits<8> val) these two produce the same output: add r0 0 add r0 256 whose responsibility is to check the integer boundary in the assembly parser? Cheers, ES -------------- next part -------------- An HTML attachment was scrubbed... URL: <http://lists.llvm.org/pipermail/llvm-dev/attachments/20151207/3fdff87e/attachment.html>
Alex Bradbury via llvm-dev
2015-Dec-07 12:24 UTC
[llvm-dev] Immediate value boundary checking
On 7 December 2015 at 11:51, Sky Flyer via llvm-dev <llvm-dev at lists.llvm.org> wrote:> Dear all, > > I have written an assembler which reads assembly instructions and produces > the equivalent binary. I have a problem. Although I set the bit range and > immediate type for an instruction like add which accepts a register and an > immediate value, I can simply overflow that value and llvm/tablegen doesn't > care! > > for example for a i8imm imm value (bits<8> val) these two produce the same > output: > > add r0 0 > add r0 256 > > whose responsibility is to check the integer boundary in the assembly > parser?It's worth looking at what some other targets do here (e.g. SystemZ handles this pretty cleanly, and MIPS is adding better error reporting http://reviews.llvm.org/D15226). It helps to take a look at include/llvm/Target/Target.td. the Operand class has a field ParserMatchClass of type AsmOperandClass, which by default contains the ImmAsmOperand instance which ultimately means that isImm() in your AsmParser will be called to check the operand. To customise the behaviour to for instance, check the immediate is in the appropriate range you can provide your own AsmOperandClass. e.g.: class ImmediateAsmOperand<string name> : AsmOperandClass { let Name = name; let RenderMethod = "addImmOperands"; let DiagnosticType = !strconcat("Invalid", name); } def imm8 : Operand<i32> { let ParserMatchClass = ImmediateAsmOperand<"Imm8">; } With the Name field of the ParserMatchClass set to Imm8, You now just need to provide an isImm8() implementation in MyTargetAsmParser. You'll also want to check for Match_InvalidImm8 as a result of MatchInstructionImpl to provide a more useful error reporting than "invalid operand for instruction". To use Match_InvalidImm8, you'll need to make sure you do something like the below (just grep the sources for GET_OPERAND_DIAGNOSTIC_TYPES to see other targets doing the same). enum MyTargetMatchResultTy { Match_Dummy = FIRST_TARGET_MATCH_RESULT_TY, #define GET_OPERAND_DIAGNOSTIC_TYPES #include "MyTargetGenAsmMatcher.inc" #undef GET_OPERAND_DIAGNOSTIC_TYPES }; I hope that helps. Best, Alex
Hi Alex, That helped a lot. I appreciate it. :-) On Mon, Dec 7, 2015 at 1:24 PM, Alex Bradbury <asb at asbradbury.org> wrote:> On 7 December 2015 at 11:51, Sky Flyer via llvm-dev > <llvm-dev at lists.llvm.org> wrote: > > Dear all, > > > > I have written an assembler which reads assembly instructions and > produces > > the equivalent binary. I have a problem. Although I set the bit range and > > immediate type for an instruction like add which accepts a register and > an > > immediate value, I can simply overflow that value and llvm/tablegen > doesn't > > care! > > > > for example for a i8imm imm value (bits<8> val) these two produce the > same > > output: > > > > add r0 0 > > add r0 256 > > > > whose responsibility is to check the integer boundary in the assembly > > parser? > > It's worth looking at what some other targets do here (e.g. SystemZ > handles this pretty cleanly, and MIPS is adding better error reporting > http://reviews.llvm.org/D15226). > > It helps to take a look at include/llvm/Target/Target.td. the Operand > class has a field ParserMatchClass of type AsmOperandClass, which by > default contains the ImmAsmOperand instance which ultimately means > that isImm() in your AsmParser will be called to check the operand. To > customise the behaviour to for instance, check the immediate is in the > appropriate range you can provide your own AsmOperandClass. e.g.: > > class ImmediateAsmOperand<string name> > : AsmOperandClass { > let Name = name; > let RenderMethod = "addImmOperands"; > let DiagnosticType = !strconcat("Invalid", name); > } > > def imm8 : Operand<i32> { > let ParserMatchClass = ImmediateAsmOperand<"Imm8">; > } > > With the Name field of the ParserMatchClass set to Imm8, You now just > need to provide an isImm8() implementation in MyTargetAsmParser. > You'll also want to check for Match_InvalidImm8 as a result of > MatchInstructionImpl to provide a more useful error reporting than > "invalid operand for instruction". To use Match_InvalidImm8, you'll > need to make sure you do something like the below (just grep the > sources for GET_OPERAND_DIAGNOSTIC_TYPES to see other targets doing > the same). > > enum MyTargetMatchResultTy { > Match_Dummy = FIRST_TARGET_MATCH_RESULT_TY, > #define GET_OPERAND_DIAGNOSTIC_TYPES > #include "MyTargetGenAsmMatcher.inc" > #undef GET_OPERAND_DIAGNOSTIC_TYPES > }; > > I hope that helps. > > Best, > > Alex >-------------- next part -------------- An HTML attachment was scrubbed... URL: <http://lists.llvm.org/pipermail/llvm-dev/attachments/20151210/b3aa460d/attachment.html>