Previously, ast transformations were performed informally as ad-hoc modifications to the generated C source code. In this commit, the same transformations are performed by rewriting the ast prior to code generation time. The most significant new transformer is transform_assignment_list. This transforms assignments such as: a, b, c = f(b, c, d) To: a = f(&b, &c, d) The former syntax is used frequently in the manual's description of FPU-related instructions.
137 lines
2.1 KiB
C
137 lines
2.1 KiB
C
#pragma once
|
|
#include <stdint.h>
|
|
#include <assert.h>
|
|
|
|
//
|
|
// sign_extend
|
|
//
|
|
|
|
static inline int32_t sign_extend(uint32_t x, uint32_t b)
|
|
{
|
|
const uint32_t m = 1UL << (b - 1);
|
|
x = x & ((1UL << b) - 1);
|
|
const int32_t r = (x ^ m) - m;
|
|
return r;
|
|
}
|
|
|
|
static inline int64_t sign_extend64(uint64_t x)
|
|
{
|
|
return (int64_t)x;
|
|
}
|
|
|
|
static inline int32_t sign_extend32(uint32_t x)
|
|
{
|
|
return (int32_t)x;
|
|
}
|
|
|
|
static inline int32_t sign_extend16(uint32_t x)
|
|
{
|
|
return sign_extend(x, 16);
|
|
}
|
|
|
|
static inline int32_t sign_extend12(uint32_t x)
|
|
{
|
|
return sign_extend(x, 12);
|
|
}
|
|
|
|
static inline int32_t sign_extend8(uint32_t x)
|
|
{
|
|
return sign_extend(x, 8);
|
|
}
|
|
|
|
//
|
|
// zero_extend
|
|
//
|
|
|
|
static inline uint32_t zero_extend(uint32_t x, uint32_t b)
|
|
{
|
|
x = x & ((1ULL << b) - 1);
|
|
return x;
|
|
}
|
|
|
|
static inline uint32_t zero_extend32(uint32_t x)
|
|
{
|
|
return (uint32_t)x;
|
|
}
|
|
|
|
static inline uint32_t zero_extend16(uint32_t x)
|
|
{
|
|
return zero_extend(x, 16);
|
|
}
|
|
|
|
static inline uint32_t zero_extend8(uint32_t x)
|
|
{
|
|
return zero_extend(x, 8);
|
|
}
|
|
|
|
static inline uint32_t zero_extend5(uint32_t x)
|
|
{
|
|
return zero_extend(x, 5);
|
|
}
|
|
|
|
static inline uint32_t zero_extend4(uint32_t x)
|
|
{
|
|
return zero_extend(x, 4);
|
|
}
|
|
|
|
static inline uint32_t zero_extend1(uint32_t x)
|
|
{
|
|
return zero_extend(x, 1);
|
|
}
|
|
|
|
//
|
|
// signed_saturate
|
|
//
|
|
|
|
static inline uint64_t signed_saturate(uint64_t x, uint32_t b)
|
|
{
|
|
const int64_t upper = (1LL << (b - 1)) - 1;
|
|
const int64_t lower = -(1LL << (b - 1));
|
|
static_assert(-(1LL << (48 - 1)) < 0);
|
|
|
|
if (x > upper)
|
|
return upper;
|
|
else if (x < lower)
|
|
return lower;
|
|
else
|
|
return x;
|
|
}
|
|
|
|
static inline uint64_t signed_saturate48(uint64_t x)
|
|
{
|
|
return signed_saturate(x, 48);
|
|
}
|
|
|
|
static inline uint32_t signed_saturate32(uint32_t x)
|
|
{
|
|
return signed_saturate(x, 32);
|
|
}
|
|
|
|
//
|
|
// "convenience" functions
|
|
//
|
|
|
|
static inline uint32_t _register(uint32_t x)
|
|
{
|
|
return zero_extend(x, 32);
|
|
}
|
|
|
|
static inline uint32_t bit(uint32_t x)
|
|
{
|
|
return zero_extend(x, 1);
|
|
}
|
|
|
|
//
|
|
// "operations"
|
|
//
|
|
|
|
static inline int32_t unary_int(int64_t x)
|
|
{
|
|
return x != 0;
|
|
}
|
|
|
|
static inline int64_t bit_extract(int64_t n, int64_t b, int64_t m)
|
|
{
|
|
return (n >> b) & ((1 << m) - 1);
|
|
}
|