#!/bin/sh # tms-clang -- M1 IR pipeline: clang IR, scale GEPs, optimize, normalize GEPs. # # Usage: tms-clang [-O0|-O2] [-I dir] -o OUT.ll IN.c # # -O2 (the default) scales, optimizes, then normalizes; -O0 skips the optimizer. # The output is normalized IR for llc -march=tms34010; this wrapper does not # invoke llc itself. set -eu ROOT=$(cd "$(dirname "$0")/.." && pwd) TMS_CLANG=${TMS_CLANG:-$ROOT/build/llvm-build/bin/clang} TMS_OPT=${TMS_OPT:-$ROOT/build/llvm-build/bin/opt} TMS_BITADDR=${TMS_BITADDR:-$ROOT/tools/tms-bitaddr/tms-bitaddr} OPTIMIZE=1 INCLUDES= OUT= IN= usage() { echo "usage: $0 [-O0|-O2] [-I dir] -o OUT.ll IN.c" >&2 exit 2 } while [ $# -gt 0 ]; do case "$1" in -O0) OPTIMIZE=0; shift ;; -O2) OPTIMIZE=1; shift ;; -I) [ $# -ge 2 ] || usage; INCLUDES="$INCLUDES -I $2"; shift 2 ;; -I*) INCLUDES="$INCLUDES $1"; shift ;; -o) [ $# -ge 2 ] || usage; OUT=$2; shift 2 ;; -*) usage ;; *) [ -z "$IN" ] || usage; IN=$1; shift ;; esac done [ -n "$IN" ] || usage [ -n "$OUT" ] || usage TMP=$(mktemp -d "${TMPDIR:-/tmp}/tms-clang.XXXXXX") trap 'rm -rf "$TMP"' EXIT HUP INT TERM # shellcheck disable=SC2086 "$TMS_CLANG" --target=tms34010-unknown-none -O0 -Xclang -disable-O0-optnone \ -S -emit-llvm -ffreestanding -fno-builtin -nostdinc $INCLUDES \ -o "$TMP/step1.ll" "$IN" "$TMS_BITADDR" --scale "$TMP/step1.ll" "$TMP/scaled.ll" 2>/dev/null if [ "$OPTIMIZE" -eq 1 ]; then # This target has no i64 and no multiply-high, so IndVarSimplify's # exit-value replacement (which rewrites a loop's final value into a # closed-form i33 multiply, e.g. n*(n+1)/2 for sumto) produces IR that # llc cannot select. -replexitval is an option of IndVarSimplify; disabling # only that rewrite keeps the loop, which is what ordinary -O2 code needs. # This is a driver policy, not a target TTI policy: opt runs without a # target machine here. # `-switch-to-lookup=false` is a driver policy, not a target feature: the # optimizer's switch-to-lookup-table transform creates a *new* byte-offset # GEP after --scale, and --normalize can only treat late GEP offsets as # bit offsets. Such a GEP would index the table one bit per slot (an 8x # address bug). The backend also has no jump-table lowering, so keeping # the compare/branch switch is correct. "$TMS_OPT" -passes='default' -replexitval=never \ -switch-to-lookup=false -S "$TMP/scaled.ll" -o "$TMP/opt.ll" NORMALIZE_IN="$TMP/opt.ll" else NORMALIZE_IN="$TMP/scaled.ll" fi mkdir -p "$(dirname "$OUT")" "$TMS_BITADDR" --normalize "$NORMALIZE_IN" "$OUT" 2>/dev/null