HN user

cokernel_hacker

1,316 karma
Posts54
Comments122
View on HN
www.sciencedaily.com 1mo ago

Scientists complete Schrödinger's 100-year-old color theory

cokernel_hacker
5pts1
www.sigasi.com 3mo ago

VHDL's Crown Jewel

cokernel_hacker
149pts62
ionathan.ch 4mo ago

U+237C ⍼ Is Azimuth

cokernel_hacker
402pts81
thottingal.in 4mo ago

Variable interpolatable smooth curves and outlines

cokernel_hacker
3pts0
pmc.ncbi.nlm.nih.gov 1y ago

The non-Riemannian nature of perceptual color space

cokernel_hacker
2pts0
www.spiedigitallibrary.org 1y ago

EUV LLC: An Historical Perspective

cokernel_hacker
1pts1
blog.quarticcat.com 1y ago

RVV may not be as good as you think

cokernel_hacker
1pts0
saagarjha.com 2y ago

Designing a Better Strcpy

cokernel_hacker
8pts0
www.open-std.org 2y ago

P3292R0R0 Provenance and Concurrency

cokernel_hacker
2pts0
zenorogue.medium.com 2y ago

Non-Euclidean Geometry and Games

cokernel_hacker
2pts0
en.wikipedia.org 2y ago

The Goodyear Massively Parallel Processor

cokernel_hacker
5pts0
uxlfoundation.org 2y ago

UXL Foundation: Unified Acceleration

cokernel_hacker
1pts0
conal.net 2y ago

The C language is purely functional

cokernel_hacker
3pts0
www.geoffchappell.com 2y ago

Windows 3.1 in a Windows 95 Virtual Machine

cokernel_hacker
3pts0
vimeo.com 2y ago

Life at Both Ends of the Barrel: An NSA Targeting Retrospective [video]

cokernel_hacker
1pts0
cs.uwaterloo.ca 2y ago

What This Country Needs is an 18¢ Piece (2002) [pdf]

cokernel_hacker
145pts272
extremelearning.com.au 2y ago

Going Beyond the Golden Ratio

cokernel_hacker
2pts0
robertheaton.com 2y ago

Making Peace with Simpson's Paradox

cokernel_hacker
3pts0
www.oranlooney.com 2y ago

Cracking Playfair Ciphers

cokernel_hacker
3pts0
frama-c.com 3y ago

Correct rounding or mathematically-correct rounding?

cokernel_hacker
1pts0
taskandpurpose.com 3y ago

The Army once built an underground ice fortress during the Cold War

cokernel_hacker
3pts0
pfalcon.github.io 3y ago

SSA-based Compiler Design [pdf]

cokernel_hacker
1pts0
blog.stuffedcow.net 3y ago

TLB and Pagewalk Coherence in x86 Processors

cokernel_hacker
1pts0
www.gpsrchive.com 3y ago

GPS vs. Glonass vs. Galileo

cokernel_hacker
228pts81
pathfinder.intel.com 3y ago

Intel Pathfinder for RISC-V

cokernel_hacker
3pts0
www.axios.com 4y ago

Nobel Prize awarded for research on how humans feel temperature and touch

cokernel_hacker
1pts0
travisdowns.github.io 4y ago

Ice Lake Store Elimination

cokernel_hacker
2pts0
conventionalcomments.org 4y ago

Conventional Comments

cokernel_hacker
2pts0
ridiculousfish.com 4y ago

Labor of Division (Episode VI): Narrowing Division Insight and Benchmarks

cokernel_hacker
1pts0
www.wsj.com 4y ago

Apple Trial Ends in Mixed Verdict After Epic’s Monopoly Allegations

cokernel_hacker
66pts10
Obituary for Cyc 1 year ago

What if it breaks in a way which renders it no longer a chair for you but not others?

This seems to imply that what is or is not a chair is a subjective or conditional.

With chip fabrication technology in the spotlight lately, this book chapter on the history of EUV development and DARPA's role might be of interest to some.

So let's change it up a bit.

  typedef int (*pfn)(void);
  int g(void);
  int h(void);

  pfn f(double x) {
    switch ((long long)x) {
    case 0:
      return g;
    case 17:
      return h;
    }
  }

If I understand your perspective correctly, `f` should return whatever happens to be in rax if the caller does not pass in a number which truncates to 0 or 17?

What behavior should the following have:

  int f(int x) {
    switch (x) {
    case 0:
      return 31;
    case 1:
      return 28;
    case 2:
      return 30;
    }
  }
This code on its own has no undefined behavior.

In another translation unit, someone calls `f(3)`. What would you have compilers do in that case?

That path through the program has undefined behavior. However, the two translation units are separate and as such normal tooling will not be able to detect any sort of UB without some kind of whole program static analysis or heavy instrumentation which would harm performance.

I particularly liked the "Windows" vs "Sindogs" issue. My immediate hunch was that the characters differed by a single bit so I ran a bit of python:

  >>> [ord(x) ^ ord(y) for (x, y) in zip("windows", "sindogs")]
  [4, 0, 0, 0, 0, 16, 0]
Sure enough...

The conclusions section of the paper is a good summary:

"In the process, we learned ten lessons about DSAs and DNNs in general and about DNN DSAs specifically that shaped the design of TPUv4i:

1. Logic improves more quickly than wires and SRAM ⇒ TPUv4i has 4 MXUs per core vs 2 for TPUv3 and 1 for TPUv1/v2.

2. Leverage existing compiler optimizations ⇒ TPUv4i evolved from TPUv3 instead of being a brand new ISA.

3. Design for perf/TCO instead of perf/CapEx ⇒ TDP is low, CMEM/HBM are fast, and the die is not big.

4. Backwards ML compatibility enables rapid deployment of trained DNNs ⇒TPUv4i supports bf16 and avoids arithmetic problems by looking like TPUv3 from the XLA compiler’s perspective.

5. Inference DSAs need air cooling for global scale ⇒ Its design and 1.0 GHz clock lowers its TDP to 175W.

6. Some inference apps need floating point arithmetic ⇒ It supports bf16 and int8, so quantization is optional.

7. Production inference normally needs multi-tenancy ⇒ TPUv4i’s HBM capacity can support multiple tenants.

8. DNNs grow ~1.5x annually in memory and compute ⇒ To support DNN growth, TPUv4i has 4 MXUs, fast onand off-chip memory, and ICI to link 4 adjacent TPUs.

9. DNN workloads evolve with DNN breakthroughs ⇒ Its programmability and software stack help pace DNNs.

10. The inference SLO is P99 latency, not batch size ⇒ Backwards ML compatible training tailors DNNs to TPUv4i, yielding batch sizes of 8–128 that raise throughput and meet SLOs. Applications do not restrict batch size."

There is this great document (http://www.decus.de/events/alphamigration/vortraege/porting_...) which details the efforts to go from Alpha to Itanium.

What is notable about their Itanium efforts is that they chose to use ELF and DWARF and their object file and debugging formats. I think that this was actually quite important as it made it far easier for the x86 port: LLVM has robust support for ELF & DWARF.

I think another thing which helped is that they wrote more of OpenVMS in C which avoided the need for an x86 PL/I compiler, etc.

I believe that Rice's theorem is about computability, not about whether or not it is possible to validate which CPU instructions a program can contain.

With certain restrictions, it is possible to do this: Google Native Client [1] has a verifier which checks that programs it executed did not jump into the middle of other instructions, forbade run-time code generation inside of such programs, etc.

[1] https://en.wikipedia.org/wiki/Google_Native_Client

ABI Mistakes 5 years ago

My reading of the C++ standard is that this behavior is effectively mandated and that one can write a program which can tell if an ABI observed the proposed optimization.

[expr.call]: "The lvalue-to-rvalue, array-to-pointer, and function-to-pointer standard conversions are performed on the argument expression."

[conv.lval]: "... if T has a class type, the conversion copy-initializes the result object from the glvalue."

The way a program can tell if a compiler is compliant to the standard is like so:

  struct S { int large[100]; };

  int compliant(struct S a, const struct S *b);

  int escape(const void *x);

  int bad() {
    struct S s;
    escape(&s);
    return compliant(s, &s);
  }

  int compliant(struct S a, const struct S *b) {
    int r = &a != b;
    escape(&a);
    escape(b);
    return r;
  }
There are three calls to 'escape'. A programmer may assume that the first and third call to escape observes a different object than the second call to escape and they may assume that 'compliant' returns '1'.

It is a project aimed at making the design of electronic logical easier.

Often, such hardware is written using hardware description languages [1] like Verilog or VHDL. These languages are very low level and, in the opinion of some, a little clumsy to use.

XLS aims to provide a system for High-level synthesis [2]. The benefit of such systems is that you can more easily map interesting algorithms to hardware without being super low level.

[1] https://en.wikipedia.org/wiki/Hardware_description_language

[2] https://en.wikipedia.org/wiki/High-level_synthesis

Interesting. One issue is treatment of 1 / -inf. This would be -0 in traditional IEEE 754 but would now be +0 IIUC.

This would imply that 1 / (1 / -inf) would now be +inf instead of -inf.

I use Google Express quite often for grabbing house hold essentials that I don't have the time to make a dedicated trip. I wonder if my habits will change now that I just need to speak up to place an order.

I also wonder if this will be one of those things which youngins' will take for granted someday...

I recently reimplemented machinery in our compiler which implements C++ exceptions. I figure it might be useful to share a few interesting issues.

The way C++ exceptions are used creates very interesting interactions in the design of their implementation.

There a hidden cost many forget: call frame information restricts what the compiler can do. Why is this the case? Even if exceptions are super rare, the compiler still needs to make sure the program will obey the language rules if an exception is somehow thrown at an appropriate program point.

The compiler must emit instructions which can be represented by the call frame information in order for the unwind to be able to reason about the stack.

This is usually not a problem on Linux because the DWARF CFI is very expressive. That expressiveness comes at a cost: it is quite inefficient when it comes to size.

Other platforms, Windows NT (ARM, x64 and IPF) and iOS, recognized that this increase in size is a bad state of affairs and thus aimed to make the CFI more compact. By doing this, they greatly reduced the size of CFI but unfortunately created restrictions on what a compiler can do.

As for trickiness inherent in C++ exceptions, C++ supports a fairly esoteric feature: exceptions may be rethrown without being in a try or catch:

  void rethrow() {
    throw;
  }
An easy way to make this sort of thing work would be to thread a secret in/out parameter which represents the exception state.

But how is this typically implemented?

Well, remember, the ethos of exceptions in C++ is that they are rare. Rare enough that implementors are discouraged from optimizing the speed of C++ exceptions.

Instead, thread local storage is typically used to go from any particular thread back to it's context.

Things get pretty darn complicated pretty quickly with features like dynamic exception specifications:

  void callee() throw(double) {
    throw 0;
  }
  void caller() {
    try {
      callee();
    } catch (...) {
      puts("got here!");
    }
  }
On first examination, "got here!" should be unreachable because the call to "callee" results in a violation of the exception specification.

However, this is not necessarily the case! What _actually_ happens is that some code runs between the throw and the catch: std::unexpected is called.

Now, std::unexpected might throw an exception of it's own! If this new exception matches the exception specification, the exception would pass into the catch block in "caller". If it doesn't, the exception thrown within std::unexpected might result in another violation!

Wow, this is get complicated... OK, so what happens if it results in another violation? Well, the exception gets cleaned up and replaced with, you guessed it, another exception! We'd be left with an exception of type std::bad_exception leaving std::unexpected and thus "callee". Because the catch clause in "caller" is compatible with std::bad_exception, control is transferred to the catch block.

This is the tip of the iceberg. A huge amount of machinery is sitting around, waiting to engage to make exceptions work.

Professional compiler engineer here, C is a mediocre intermediate language.

Let's start with an excellent quote from Wittgenstein. "The limits of my language mean the limits of my world."

Using C as your intermediate language means that your expressiveness is limited to valid C programs. This is workable but only if your language can be mapped to C in _useful_ ways.

For example, let's say your language has behavior similar to scheme's tail-call. How would you get this behavior from a C compiler? You will never be able to make this reliably across optimization levels, etc.

Guaranteed tail-calls are the tip of the iceberg, there are a lot more features which cannot be reasonably mapped onto C.

Real compiler IRs increase your expressivity beyond what the C language designers decided was important.