A clause with nested conditionals

c_lower.pl: an if-then-else whose branch holds another, drawn as a flow.

251define_globalSym, Type, Linkage, Init, Loc, Env0, Env ←
env_defsEnv0, Defs
get_assocgdefSym, Defs, g_, _, Init0, _
Init0 ≢ none
→
Init ≡ none
→
Env = Env0
else
sema_errorLoc, '~w is initialized twice', Sym
else
put_defgdefSym, gType, Linkage, Init, Loc, Env0, Env

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.

usual_arith_conversion+TypeA, +TypeB, -Typesemidet
TypeAinthe type of one arithmetic operand
TypeBinthe type of the other
Typeouttheir 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.

examples 8/8 hold
✓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
935usual_arith_conversionTypeA0, TypeB0, Type ←
TypeA0 ≡ double
or
TypeB0 ≡ double
!
Type = double
939usual_arith_conversionTypeA0, TypeB0, float ←
TypeA0 ≡ float
or
TypeB0 ≡ float
!
942usual_arith_conversionTypeA0, TypeB0, Type ←
int_infoA, SizeA, SignA
int_infoB, SizeB, SignB
rankA, RankA
rankB, RankB
A ≡ B
→
Type = A
SignA ≡ SignB
→
RankA ≥ RankB
→
Type = A
else
Type = B
SignA ≡ unsigned
RankA ≥ RankB
→
Type = A
SignB ≡ unsigned
RankB ≥ RankA
→
Type = B
SignA ≡ signed
SizeA > SizeB
→
Type = A
SignB ≡ signed
SizeB > SizeA
→
Type = B
SignA ≡ signed
→
else

Lists, tails and a DCG

c_pp.pl: list patterns with tails, terminals, {} goals and operators.

located_splice+Chars, +Loc, -Spliced, -Locs

remove backslash-newline and give each remaining character its physical location.

118located_splice\, '\r', '\n'|Cs, File:N, Spliced, Locs ←
!
N1 is N + 1
located_spliceCs, File:N1, Spliced, Locs
121located_splice\, '\n'|Cs, File:N, Spliced, Locs ←
!
N1 is N + 1
located_spliceCs, File:N1, Spliced, Locs

Share one location term per physical line, not one per character.

125located_spliceC|Cs, Loc, C|Spliced, Loc|Locs ←
!
C ≡ '\n'
→
Loc = File:N
N1 is N + 1
Loc1 = File:N1
else
Loc1 = Loc
located_spliceCs, Loc1, Spliced, Locs
133located_splice[], _, [], []
pp_tokensPpTokens, Locs, Space

Locs runs in step with the input characters; Space says whether whitespace precedes the next token.

137pp_tokensnl|Ts, _|Locs, _ ⟶
'\n'
!
pp_tokensTs, Locs, yes
140pp_tokensTs, _|Locs, _ ⟶
C
!
pp_tokensTs, Locs, yes
143pp_tokensTs, _, _|Locs, _ ⟶
/, /
!
line_commentLocs, Rest
pp_tokensTs, Rest, yes
147pp_tokensTs, _, _|Locs, _ ⟶
/, *
!
block_commentLocs, Rest
pp_tokensTs, Rest, yes
151pp_tokenstA, Loc, Space, []|Ts, Loc|Locs, Space ⟶
!
atom_charsA, Cs
lengthCs, N
N1 is N−1
dropN1, Locs, Rest
pp_tokensTs, Rest, no
159pp_tokens[], [], _ ⟶
[]

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
start:10 ops
let%v1, p, alloc4, const4
let%v3, p, alloc4, const4
let%v5, p, alloc4, const4
storew, %v0, %v1
storew, %v2, %v3
storew, %v4, %v5
let%v9, w, loadsw, %v1
let%v10, w, loadsw, %v3
let%v11, w, cmpslt, w, %v9, %v10
branch%v11, 'L6', 'L7'
L6:2 ops
let%v12, w, loadsw, %v3
goto'L8'
L7:4 ops
let%v16, w, loadsw, %v1
let%v17, w, loadsw, %v5
let%v18, w, cmpsgt, w, %v16, %v17
branch%v18, 'L13', 'L14'
L13:2 ops
let%v19, w, loadsw, %v5
goto'L15'
L14:2 ops
let%v20, w, loadsw, %v1
goto'L15'
L15:2 ops
phi%v21, w, 'L13'−%v19, 'L14'−%v20
goto'L8'
L8:2 ops
phi%v22, w, 'L6'−%v12, 'L15'−%v21
ret%v22

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
start:9 ops
C · 2int sum(const int *xs, int n) {
let&xs0, p, alloc8, const8
let&n0, p, alloc4, const4
C · 3int total = 0;
let&total0, p, alloc4, const4
C · 4for (int i = 0; i < n; i++)
let&i0, p, alloc4, const4
C · 2int sum(const int *xs, int n) {
storep, xs0, &xs0
storew, n0, &n0
C · 3int total = 0;
storew, const0, &total0
C · 4for (int i = 0; i < n; i++)
storew, const0, &i0
goto'L6'
L6:4 ops
C · 4for (int i = 0; i < n; i++)
leti0, w, loadsw, &i0
letn1, w, loadsw, &n0
let%v12, w, cmpslt, w, i0, n1
branch%v12, 'L7', 'L9'
L7:12 ops
C · 5total += xs[i] * 2 + 1;
lettotal0, w, loadsw, &total0
letxs1, p, loadp, &xs0
leti1, w, loadsw, &i0
let%v16, l, extsw, i1
let%v17, l, mul, %v16, const4
let%v18, p, add, xs1, %v17
let%v19, w, loadsw, %v18
let%v20, w, mul, %v19, const2
let%v21, w, add, %v20, const1
lettotal1, w, add, total0, %v21
storew, total1, &total0
C · 4for (int i = 0; i < n; i++)
goto'L8'
L8:4 ops
C · 4for (int i = 0; i < n; i++)
leti2, w, loadsw, &i0
leti3, w, add, i2, const1
storew, i3, &i0
goto'L6'
L9:2 ops
C · 6return total;
lettotal2, w, loadsw, &total0
rettotal2

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
start:1 ops
C · 4for (int i = 0; i < n; i++)
goto'L6'
L6:4 ops
C · 4for (int i = 0; i < n; i++)
phii4, w, 'L8'−i3, start−const0
phitotal3, w, 'L8'−total1, start−const0
C · 4for (int i = 0; i < n; i++)
let%v12, w, cmpslt, w, i4, n0
branch%v12, 'L7', 'L9'
L7:8 ops
C · 5total += xs[i] * 2 + 1;
let%v16, l, extsw, i4
let%v17, l, mul, %v16, const4
let%v18, p, add, xs0, %v17
let%v19, w, loadsw, %v18
let%v20, w, mul, %v19, const2
let%v21, w, add, %v20, const1
lettotal1, w, add, total3, %v21
C · 4for (int i = 0; i < n; i++)
goto'L8'
L8:2 ops
C · 4for (int i = 0; i < n; i++)
leti3, w, add, i4, const1
goto'L6'
L9:1 ops
C · 6return total;
rettotal3

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_clamppizlonatedFIP17691_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.

decl'sample.c':1, sustruct, somepoint, fieldtspecint, dclsomex, base, none, none, fieldtspecint, dclsomey, base, none, none, [], []
fundef'sample.c':3, storagestatic, tspecint, dclsomeclamp, funcbase, paramsparamtspecint, dclsomev, base, none, paramtspecint, dclsomelo, base, none, paramtspecint, dclsomehi, base, none, fixed, none, at'sample.c':3, blockat'sample.c':4, returncondbinlt, idv, idlo, idlo, condbingt, idv, idhi, idhi, idv