A clause with nested conditionals
c_lower.pl: an if-then-else whose branch holds another, drawn as a flow.
Documentation, examples and cases
c_types.pl: a doc/3 signature, argument table and checked examples, then numbered clauses with a disjunction and a cut.
| TypeA | in | the type of one arithmetic operand |
| TypeB | in | the type of the other |
| Type | out | their common real type |
The usual arithmetic conversions. A floating operand wins; otherwise both are promoted, and when the signedness differs the unsigned type wins unless the signed one is wider. A signed type exactly as wide as a higher-ranked unsigned one gives way to its own unsigned type.
| ✓ | usual_arith_conversionint, double, T | ⟹ | T = double |
| ✓ | usual_arith_conversionfloat, long, T | ⟹ | T = float |
| ✓ | usual_arith_conversionchar, short, T | ⟹ | T = int |
| ✓ | usual_arith_conversionint, uint, T | ⟹ | T = uint |
| ✓ | usual_arith_conversionuint, long, T | ⟹ | T = long |
| ✓ | usual_arith_conversionlong, ullong, T | ⟹ | T = ullong |
| ✓ | usual_arith_conversionllong, ulong, T | ⟹ | T = ullong |
| ✓ | usual_arith_conversionptrint, int, _ | ⟹ | fails |
Lists, tails and a DCG
c_pp.pl: list patterns with tails, terminals, {} goals and operators.
remove backslash-newline and give each remaining character its physical location.
Share one location term per physical line, not one per character.
Locs runs in step with the input characters; Space says whether whitespace precedes the next token.
IR without source metadata
The shared playground renderer, with raw temporary identities when no C provenance is available.
How to read the IRhover a word for its meaning; a temporary, for its uses
IR machine classes (not C types)
- w
- 32-bit integer (word)
- l
- 64-bit integer (long)
- p
- pointer: an address with its Fil-C capability, the bounds it may touch
- s
- 32-bit float (single)
- d
- 64-bit float (double)
- a
- proven address: a pointer a check has cleared, for one access
- b
- 8 bits (byte), a width of memory
- h
- 16 bits (halfword), a width of memory
- void
- no value
Values
- name₀ / %tmp
- an SSA value, assigned once; the subscript counts definitions of this source name, including removed ones. &name is its address, part·name an ABI piece; a superscript distinguishes shadowed bindings. Hover for raw identity and types
- const(N)
- a constant; for a float, its IEEE bit pattern
- global(Symbol)
- the address of a function or data object
Instructions
- let(Tmp, Class, Op, Args)
- Tmp, of Class, is Op applied to Args
- phi(Tmp, Class, [From-Value, …])
- Tmp is the Value for the block control came from
- call(Result, Callee, [Arg, …])
- call a function
- result(Tmp, Class)
- where a call puts its return value
- arg(Class, Value)
- one argument of a call
- param(Class, Tmp)
- a parameter of the function
- tuple([…])
- two words returned together (a small struct)
Operations, in let
- add
- +
- sub
- −
- mul
- ×
- div
- ÷, signed
- udiv
- ÷, unsigned
- rem
- remainder, signed
- urem
- remainder, unsigned
- and
- bitwise and
- or
- bitwise or
- xor
- bitwise exclusive or
- shl
- shift left
- shr
- shift right, filling with zeros (unsigned)
- sar
- shift right, keeping the sign (signed)
- neg
- negate
- copy
- the value itself; of a global, a pointer to it
- cmp(Cond, Class)
- compare two Class values: 1 if Cond holds, else 0
- ext(Type)
- widen a Type value to the result's class
- truncd
- double to single
- stosi
- single to signed integer
- stoui
- single to unsigned integer
- dtosi
- double to signed integer
- dtoui
- double to unsigned integer
- swtof
- signed 32-bit integer to float
- uwtof
- unsigned 32-bit integer to float
- sltof
- signed 64-bit integer to float
- ultof
- unsigned 64-bit integer to float
- cast
- the same bits as the other class (w and s, l and d)
- ptoi
- pointer to integer: the address, without its capability
- itop
- integer to pointer, with no capability
- va_args
- a cursor into the variadic arguments
- va_arg
- the next variadic argument, moving the cursor
- setjmp(Kind)
- save the context to return to; 0 now, nonzero on longjmp
Memory
- load(Type)
- read memory; Fil-C checks the pointer first
- store(Width, Value, Pointer)
- write memory; Fil-C checks the pointer first
- alloc(Align)
- a new object for a local variable, as many bytes as its argument, aligned to Align
Fil-C's safety
- check(Lo, Hi, Rights, Align)
- stop the program unless the pointer may read or write bytes Lo to Hi past it, aligned; the result is the proven address
- raw_load(Type, Offset)
- read at a proven address plus Offset, with no check of its own
- raw_store(Width, Offset, Value, Proven)
- write at a proven address plus Offset, with no check of its own
- poll(Label)
- a safepoint on the way to Label: the collector and signal handlers may run
Jumps: how a block ends
- goto(Label)
- continue at block Label
- branch(Value, Then, Else)
- go to Then if Value is nonzero, else to Else
- ret(Value)
- return Value
- ret
- return
- rets([V1, V2])
- return two words
- unreachable
- control never gets here; if it does, the program stops
Functions and data
- func(Name, Linkage, Returns, Params, Blocks)
- a function: blocks of instructions, the first one entered
- data(Name, Linkage, Align, Items)
- a data object
- item(Width, Value)
- Width bytes of a data object
- str(Text)
- bytes, one per character
- sym(Symbol, Offset)
- the address of Symbol, plus Offset
- zero(N)
- N zero bytes
- export
- other files may use it
- local
- only this file uses it
- ro(Linkage)
- read-only data
Conditions, in cmp
- eq
- =
- ne
- ≠
- slt
- <, signed
- sle
- ≤, signed
- sgt
- >, signed
- sge
- ≥, signed
- ult
- <, unsigned
- ule
- ≤, unsigned
- ugt
- >, unsigned
- uge
- ≥, unsigned
- lt
- <
- le
- ≤
- gt
- >
- ge
- ≥
- o
- ordered: neither is NaN
- uo
- unordered: one is NaN
Narrow types, in load and ext
- sb
- signed byte
- ub
- unsigned byte
- sh
- signed 16 bits
- uh
- unsigned 16 bits
- sw
- signed 32 bits
- uw
- unsigned 32 bits
funcclamp, local, w, paramw, %v0, paramw, %v2, paramw, %v4, Blocks
C names, lowered IR
Actual compiler output for the playground's sum.c. Subscripts count SSA definitions, & marks an address; hover for raw identity, IR class, C expression type and C binding type.
How to read the IRhover a word for its meaning; a temporary, for its uses
IR machine classes (not C types)
- w
- 32-bit integer (word)
- l
- 64-bit integer (long)
- p
- pointer: an address with its Fil-C capability, the bounds it may touch
- s
- 32-bit float (single)
- d
- 64-bit float (double)
- a
- proven address: a pointer a check has cleared, for one access
- b
- 8 bits (byte), a width of memory
- h
- 16 bits (halfword), a width of memory
- void
- no value
Values
- name₀ / %tmp
- an SSA value, assigned once; the subscript counts definitions of this source name, including removed ones. &name is its address, part·name an ABI piece; a superscript distinguishes shadowed bindings. Hover for raw identity and types
- const(N)
- a constant; for a float, its IEEE bit pattern
- global(Symbol)
- the address of a function or data object
Instructions
- let(Tmp, Class, Op, Args)
- Tmp, of Class, is Op applied to Args
- phi(Tmp, Class, [From-Value, …])
- Tmp is the Value for the block control came from
- call(Result, Callee, [Arg, …])
- call a function
- result(Tmp, Class)
- where a call puts its return value
- arg(Class, Value)
- one argument of a call
- param(Class, Tmp)
- a parameter of the function
- tuple([…])
- two words returned together (a small struct)
Operations, in let
- add
- +
- sub
- −
- mul
- ×
- div
- ÷, signed
- udiv
- ÷, unsigned
- rem
- remainder, signed
- urem
- remainder, unsigned
- and
- bitwise and
- or
- bitwise or
- xor
- bitwise exclusive or
- shl
- shift left
- shr
- shift right, filling with zeros (unsigned)
- sar
- shift right, keeping the sign (signed)
- neg
- negate
- copy
- the value itself; of a global, a pointer to it
- cmp(Cond, Class)
- compare two Class values: 1 if Cond holds, else 0
- ext(Type)
- widen a Type value to the result's class
- truncd
- double to single
- stosi
- single to signed integer
- stoui
- single to unsigned integer
- dtosi
- double to signed integer
- dtoui
- double to unsigned integer
- swtof
- signed 32-bit integer to float
- uwtof
- unsigned 32-bit integer to float
- sltof
- signed 64-bit integer to float
- ultof
- unsigned 64-bit integer to float
- cast
- the same bits as the other class (w and s, l and d)
- ptoi
- pointer to integer: the address, without its capability
- itop
- integer to pointer, with no capability
- va_args
- a cursor into the variadic arguments
- va_arg
- the next variadic argument, moving the cursor
- setjmp(Kind)
- save the context to return to; 0 now, nonzero on longjmp
Memory
- load(Type)
- read memory; Fil-C checks the pointer first
- store(Width, Value, Pointer)
- write memory; Fil-C checks the pointer first
- alloc(Align)
- a new object for a local variable, as many bytes as its argument, aligned to Align
Fil-C's safety
- check(Lo, Hi, Rights, Align)
- stop the program unless the pointer may read or write bytes Lo to Hi past it, aligned; the result is the proven address
- raw_load(Type, Offset)
- read at a proven address plus Offset, with no check of its own
- raw_store(Width, Offset, Value, Proven)
- write at a proven address plus Offset, with no check of its own
- poll(Label)
- a safepoint on the way to Label: the collector and signal handlers may run
Jumps: how a block ends
- goto(Label)
- continue at block Label
- branch(Value, Then, Else)
- go to Then if Value is nonzero, else to Else
- ret(Value)
- return Value
- ret
- return
- rets([V1, V2])
- return two words
- unreachable
- control never gets here; if it does, the program stops
Functions and data
- func(Name, Linkage, Returns, Params, Blocks)
- a function: blocks of instructions, the first one entered
- data(Name, Linkage, Align, Items)
- a data object
- item(Width, Value)
- Width bytes of a data object
- str(Text)
- bytes, one per character
- sym(Symbol, Offset)
- the address of Symbol, plus Offset
- zero(N)
- N zero bytes
- export
- other files may use it
- local
- only this file uses it
- ro(Linkage)
- read-only data
Conditions, in cmp
- eq
- =
- ne
- ≠
- slt
- <, signed
- sle
- ≤, signed
- sgt
- >, signed
- sge
- ≥, signed
- ult
- <, unsigned
- ule
- ≤, unsigned
- ugt
- >, unsigned
- uge
- ≥, unsigned
- lt
- <
- le
- ≤
- gt
- >
- ge
- ≥
- o
- ordered: neither is NaN
- uo
- unordered: one is NaN
Narrow types, in load and ext
- sb
- signed byte
- ub
- unsigned byte
- sh
- signed 16 bits
- uh
- unsigned 16 bits
- sw
- signed 32 bits
- uw
- unsigned 32 bits
funcsum, export, w, paramp, xs0, paramw, n0, Blocks
int sum(const int *xs, int n) {int total = 0;for (int i = 0; i < n; i++)int sum(const int *xs, int n) {int total = 0;for (int i = 0; i < n; i++)for (int i = 0; i < n; i++)total += xs[i] * 2 + 1;for (int i = 0; i < n; i++)for (int i = 0; i < n; i++)return total;The same loop after optimization
Actual -O output. Historical definitions reserve their subscripts, and source hints follow the surviving sites rather than instruction positions in the old listing.
How to read the IRhover a word for its meaning; a temporary, for its uses
IR machine classes (not C types)
- w
- 32-bit integer (word)
- l
- 64-bit integer (long)
- p
- pointer: an address with its Fil-C capability, the bounds it may touch
- s
- 32-bit float (single)
- d
- 64-bit float (double)
- a
- proven address: a pointer a check has cleared, for one access
- b
- 8 bits (byte), a width of memory
- h
- 16 bits (halfword), a width of memory
- void
- no value
Values
- name₀ / %tmp
- an SSA value, assigned once; the subscript counts definitions of this source name, including removed ones. &name is its address, part·name an ABI piece; a superscript distinguishes shadowed bindings. Hover for raw identity and types
- const(N)
- a constant; for a float, its IEEE bit pattern
- global(Symbol)
- the address of a function or data object
Instructions
- let(Tmp, Class, Op, Args)
- Tmp, of Class, is Op applied to Args
- phi(Tmp, Class, [From-Value, …])
- Tmp is the Value for the block control came from
- call(Result, Callee, [Arg, …])
- call a function
- result(Tmp, Class)
- where a call puts its return value
- arg(Class, Value)
- one argument of a call
- param(Class, Tmp)
- a parameter of the function
- tuple([…])
- two words returned together (a small struct)
Operations, in let
- add
- +
- sub
- −
- mul
- ×
- div
- ÷, signed
- udiv
- ÷, unsigned
- rem
- remainder, signed
- urem
- remainder, unsigned
- and
- bitwise and
- or
- bitwise or
- xor
- bitwise exclusive or
- shl
- shift left
- shr
- shift right, filling with zeros (unsigned)
- sar
- shift right, keeping the sign (signed)
- neg
- negate
- copy
- the value itself; of a global, a pointer to it
- cmp(Cond, Class)
- compare two Class values: 1 if Cond holds, else 0
- ext(Type)
- widen a Type value to the result's class
- truncd
- double to single
- stosi
- single to signed integer
- stoui
- single to unsigned integer
- dtosi
- double to signed integer
- dtoui
- double to unsigned integer
- swtof
- signed 32-bit integer to float
- uwtof
- unsigned 32-bit integer to float
- sltof
- signed 64-bit integer to float
- ultof
- unsigned 64-bit integer to float
- cast
- the same bits as the other class (w and s, l and d)
- ptoi
- pointer to integer: the address, without its capability
- itop
- integer to pointer, with no capability
- va_args
- a cursor into the variadic arguments
- va_arg
- the next variadic argument, moving the cursor
- setjmp(Kind)
- save the context to return to; 0 now, nonzero on longjmp
Memory
- load(Type)
- read memory; Fil-C checks the pointer first
- store(Width, Value, Pointer)
- write memory; Fil-C checks the pointer first
- alloc(Align)
- a new object for a local variable, as many bytes as its argument, aligned to Align
Fil-C's safety
- check(Lo, Hi, Rights, Align)
- stop the program unless the pointer may read or write bytes Lo to Hi past it, aligned; the result is the proven address
- raw_load(Type, Offset)
- read at a proven address plus Offset, with no check of its own
- raw_store(Width, Offset, Value, Proven)
- write at a proven address plus Offset, with no check of its own
- poll(Label)
- a safepoint on the way to Label: the collector and signal handlers may run
Jumps: how a block ends
- goto(Label)
- continue at block Label
- branch(Value, Then, Else)
- go to Then if Value is nonzero, else to Else
- ret(Value)
- return Value
- ret
- return
- rets([V1, V2])
- return two words
- unreachable
- control never gets here; if it does, the program stops
Functions and data
- func(Name, Linkage, Returns, Params, Blocks)
- a function: blocks of instructions, the first one entered
- data(Name, Linkage, Align, Items)
- a data object
- item(Width, Value)
- Width bytes of a data object
- str(Text)
- bytes, one per character
- sym(Symbol, Offset)
- the address of Symbol, plus Offset
- zero(N)
- N zero bytes
- export
- other files may use it
- local
- only this file uses it
- ro(Linkage)
- read-only data
Conditions, in cmp
- eq
- =
- ne
- ≠
- slt
- <, signed
- sle
- ≤, signed
- sgt
- >, signed
- sge
- ≥, signed
- ult
- <, unsigned
- ule
- ≤, unsigned
- ugt
- >, unsigned
- uge
- ≥, unsigned
- lt
- <
- le
- ≤
- gt
- >
- ge
- ≥
- o
- ordered: neither is NaN
- uo
- unordered: one is NaN
Narrow types, in load and ext
- sb
- signed byte
- ub
- unsigned byte
- sh
- signed 16 bits
- uh
- unsigned 16 bits
- sw
- signed 32 bits
- uw
- unsigned 32 bits
funcsum, export, w, paramp, xs0, paramw, n0, Blocks
for (int i = 0; i < n; i++)for (int i = 0; i < n; i++)for (int i = 0; i < n; i++)total += xs[i] * 2 + 1;for (int i = 0; i < n; i++)for (int i = 0; i < n; i++)return total;Assembly
asm.pl line terms beside the AT&T lines they print as.
| sectiontext | .text |
| p2align4 | .p2align 4 |
| typepizlonatedFIP17691_clamp, function | .type pizlonatedFIP17691_clamp, @function |
| labelpizlonatedFIP17691_clamp | pizlonatedFIP17691_clamp: |
| inspush, q, regrbp | pushq %rbp |
| insmov, q, regrsp, regrbp | movq %rsp, %rbp |
| inssub, q, imm128, regrsp | subq $128, %rsp |
| inscmp, q, regrsp, mem0, rdi | cmpq %rsp, (%rdi) |
| insjae, none, pltfilc_stack_overflow_failure | jae filc_stack_overflow_failure@PLT |
| insmov, q, regrdi, mem-72, rbp | movq %rdi, -72(%rbp) |
| insxor, l, regeax, regeax | xorl %eax, %eax |
| insmov, q, regrax, mem-104, rbp | movq %rax, -104(%rbp) |
| insmov, q, regrax, mem-96, rbp | movq %rax, -96(%rbp) |
| insmov, q, regrax, mem-88, rbp | movq %rax, -88(%rbp) |
| insmov, q, mem16, rdi, regrax | movq 16(%rdi), %rax |
| insmov, q, regrax, mem-120, rbp | movq %rax, -120(%rbp) |
| inslea, q, rip'.Lclamp..origin_c', regrax | leaq .Lclamp..origin_c(%rip), %rax |
| insmov, q, regrax, mem-112, rbp | movq %rax, -112(%rbp) |
| inslea, q, mem-120, rbp, regrax | leaq -120(%rbp), %rax |
| insmov, q, regrax, mem16, rdi | movq %rax, 16(%rdi) |
| insmov, q, regrdx, mem-8, rbp | movq %rdx, -8(%rbp) |
| insmov, q, regrcx, mem-16, rbp | movq %rcx, -16(%rbp) |
| insmov, q, regr8, mem-24, rbp | movq %r8, -24(%rbp) |
| label'.Lclamp.start' | .Lclamp.start: |
| insmovabs, q, imm4, regrsi | movabsq $4, %rsi |
| insmov, q, mem-72, rbp, regrdi | movq -72(%rbp), %rdi |
C syntax
c_parse/2's terms for a struct and a function: long terms of terms.