ihusar
2009-Jun-24 12:47 UTC
[LLVMdev] LLVM frontend supporting arbitrary bit-width integral datatypes
On Thu, 04 Jun 2009 22:55:04 +0200, Pertti Kellomäki <pertti.kellomaki at tut.fi> wrote:> Hi Adam, > > John is right, the TCE stuff would be useful for you. Our > compiler targets a processor template that the designer can > populate pretty freely. The compiler then reads the architecture > description and creates an LLVM backend on the fly. > > Please don't hesitate to get in touch with us if you have > questions.Hello, thank you for your answers, in fact, the TCE project is quite similar to our project Lissom (http://www.fit.vutbr.cz/research/view_product.php.en?id=52¬itle=1), I will take a closer look at it. One problem, I was trying to solve was, that I need to declare variables of let's say 5-bit width like 'i5 var', the maximal bit-width may be limited to 64 bits. I need such variables to represent instruction's operands, example is at the end this message. For now, I did not find any usable compiler frontend. First attempt was quite old Valen-C based on SUIF compiler which requires unavailable version of SUIF and would be hard to make work. Second attempt was SpecC reference compiler - as most of high-level language synthetizers, turns arbitrary bit-width integers into C++ templates which makes it unusable. Then few other attempts, but not much luck. The conclusion is, that I will need to modify some compiler frontend by my own, propably the clang. Please, if you have some info afout this or if anyone has already tried such thing, could you write it here? Also, is there anything I should be aware of when modifing the clang? Are there some passes, that are made only for the standard C datatypes? Stuff like sizeof() and C pointer arithmetics can be forbidden integers which bit width is not divisible by 8. Thank you Adam (I am posting this both to the llvmdev and clangdev, sry for possible spamming.) Example of why do I need arbitrary bit-width integers: I can extract from our architecture description language ISAC code, that for each instruction tells what it does: Syntax: MIPS instrucion ADDDI "ADDI" reg(0) "," reg(1) "," imm(2) Semantics: unsigned int gpregs[32]; void instr_direct_rri$op_addi$imm16$() { int op_arithm_imm = 0x08; { int rt = 1; { int rs = 28; { short imm16 = imm_i16(2); //--- intrinsics, represents instruction's immediate operand { { int simm = ((int)(imm16) << (32 - (16))) >> (32 - (16)); switch (op_arithm_imm) { //.... case 0x08: case 0x09: {if (rt != 0) gpregs[(rt)] = (( (((rs) != 0)?gpregs[(rs)]:0) ) + simm);}; break; case 0x0A: {if (rt != 0) gpregs[(rt)] = (( (((rs) != 0)?gpregs[(rs)]:0) ) < simm);}; break; //.... } }}}}} } Compile it with LLVM or any other compiler and get optimized code: ; ModuleID = 't2.c' target datalayout = "e-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f32:32:32-f64:64:64-v64:64:64-v128:128:128-a0:0:64-s0:64:64-f80:128:128" target triple = "x86_64-unknown-linux-gnu" @gpregs = common global [32 x i32] zeroinitializer, align 4 ; <[32 x i32]*> [#uses=2] define void @"instr_direct_rri$op_addi$imm16$"() nounwind { entry: %tmp = tail call i16 @llvm.immread.i16.i32(i32 2) nounwind ; <i16> [#uses=1] %shr = sext i16 %tmp to i32 ; <i32> [#uses=1] %tmp10 = load i32* getelementptr ([32 x i32]* @gpregs, i32 0, i64 28) ; <i32> [#uses=1] %add = add i32 %tmp10, %shr ; <i32> [#uses=1] store i32 %add, i32* getelementptr ([32 x i32]* @gpregs, i32 0, i64 1) ret void } This I can quite easily transform to instruction selection rule: set(reg, add(reg, sext(32, imm))) which is then used by compiler backend generator, so the code selector can then use instruction ADDI. The problem is, that the only supported types now are i8, i16 and i32 (and floating in the future). If the processor designer would like to have 12-bit operand, I need to turn it into 16-bit and then the compiler would generate useless code for extension/truncation and extracted code selection rule would not be correct.
Eli Friedman
2009-Jun-24 12:59 UTC
[LLVMdev] LLVM frontend supporting arbitrary bit-width integral datatypes
On Wed, Jun 24, 2009 at 5:47 AM, ihusar<ihusar at fit.vutbr.cz> wrote:> The conclusion is, that I will need to modify some compiler frontend by my own, propably the clang. > Please, if you have some info afout this or if anyone has already tried such thing, could you write it here? > Also, is there anything I should be aware of when modifing the clang? Are there some passes, that are > made only for the standard C datatypes? > Stuff like sizeof() and C pointer arithmetics can be forbidden integers which bit width is not divisible by 8.clang already has some code for types like this, but there isn't any way to declare such a type yet. Patches welcome, or I'll probably get around to writing it at some point. (If you have any additional questions about that, please direct them to cfe-dev only.) -Eli
Duncan Sands
2009-Jun-24 13:23 UTC
[LLVMdev] LLVM frontend supporting arbitrary bit-width integral datatypes
Hi Adam,> One problem, I was trying to solve was, that I need to declare variables of let's say 5-bit width like 'i5 var', > the maximal bit-width may be limited to 64 bits. I need such variables to represent instruction's operands, > example is at the end this message.any standard compliant C compiler supports i5, believe it or not. Try this: #include <stdio.h> struct i3 { int i:3; }; int main(void) { struct i3 A, B, C; A.i = 2; B.i = 3; C.i = A.i + B.i; printf("%d + %d = %d\n", A.i, B.i, C.i); return 0; } I get: 2 + 3 = -3 which is correct for i3 arithmetic! There might be some problems with signed vs unsigned bitfields, depending on the compiler. Ciao, Duncan.
ihusar
2009-Jun-24 15:05 UTC
[LLVMdev] LLVM frontend supporting arbitrary bit-width integral datatypes, semantics extraction
> Hi Adam, > any standard compliant C compiler supports i5, believe it or not. > > Try this: > > #include <stdio.h> > > struct i3 { int i:3; };...> Ciao, > > Duncan.Hi, i knew about this feature and i tried this already, but thank you very much for reminding it to me. I just needed to make few changes to the generated code and everything works as i expected! I was doing something wrong before, because the compiler has generated some additional code that would make problems when creating instruction selection rules. If somebody would be having similar problems, I am putting fixed example here: unsigned int gpregs[32]; struct i16 { int a:16;}; void instr_direct_rri() { int op_arithm_imm = 0x08; { int rt = 1; { int rs = 28; { struct i16 imm16; imm16.a = immread_i16(0); {{ //immread_i16 is a special builtin with return type i16 int simm = ((int)(imm16.a) << (32 - (16))) >> (32 - (16)); switch (op_arithm_imm) { case 0x08: case 0x09: {if (rt != 0) gpregs[(rt)] = (( (((rs) != 0)?gpregs[(rs)]:0) ) + simm);}; break; case 0x0A: {if (rt != 0) gpregs[(rt)] = (( (((rs) != 0)?gpregs[(rs)]:0) ) < simm);}; break; } }}}}} } After clang-cc -O3 -std=c99 tt.c -emit-llvm -o - I get: %tmp = tail call i16 @llvm.immread.i16.i32(i32 0) nounwind ; <i16> [#uses=1] %conv = sext i16 %tmp to i32 ; <i32> [#uses=1] %tmp14 = load i32* getelementptr ([32 x i32]* @gpregs, i32 0, i64 28) ; <i32> [#uses=1] %add = add i32 %tmp14, %conv ; <i32> [#uses=1] store i32 %add, i32* getelementptr ([32 x i32]* @gpregs, i32 0, i64 1) ret void that represents exactly what i needed: set(reg(1), add( reg(28), sext(32, imm(0)) ) ) Thanks a lot Adam On Wed, 24 Jun 2009 15:23:04 +0200, Duncan Sands <baldrick at free.fr> wrote:> _______________________________________________ > LLVM Developers mailing list > LLVMdev at cs.uiuc.edu http://llvm.cs.uiuc.edu > http://lists.cs.uiuc.edu/mailman/listinfo/llvmdev >
Sebastian Redl
2009-Jun-25 14:10 UTC
[LLVMdev] [cfe-dev] LLVM frontend supporting arbitrary bit-width integral datatypes
Duncan Sands wrote:> Hi Adam, > > >> One problem, I was trying to solve was, that I need to declare variables of let's say 5-bit width like 'i5 var', >> the maximal bit-width may be limited to 64 bits. I need such variables to represent instruction's operands, >> example is at the end this message. >> > > any standard compliant C compiler supports i5, believe it or not. > > Try this: > > #include <stdio.h> > > struct i3 { int i:3; }; > > int main(void) { > struct i3 A, B, C; > > A.i = 2; > B.i = 3; > C.i = A.i + B.i; > printf("%d + %d = %d\n", A.i, B.i, C.i); > return 0; > } > > I get: > 2 + 3 = -3 > which is correct for i3 arithmetic! > There might be some problems with signed vs unsigned bitfields, > depending on the compiler. >You're producing a signed overflow, which is simply undefined behavior. Unsigned overflow is well-defined, even for bitfields, but signed is not. Sebastian
Apparently Analagous Threads
- [LLVMdev] LLVM frontend supporting arbitrary bit-width integral datatypes
- [LLVMdev] [cfe-dev] LLVM frontend supporting arbitrary bit-width integral datatypes
- [LLVMdev] LLVM frontend supporting arbitrary bit-width integral datatypes
- [LLVMdev] LLVM frontend supporting arbitrary bit-width integral datatypes
- [LLVMdev] LLVM frontend supporting arbitrary bit-width integral datatypes